FullCalendar中如何按条件将拖拽事件重置回原始位置
FullCalendar拖拽确认+回退实现方案
你存储拖拽前后位置的思路可行,但FullCalendar本身提供了内置的位置回退能力,不需要手动计算、修改事件属性回退,稳定性更高,具体实现如下:
核心原理
FullCalendar的拖拽相关回调自带操作回滚方法:
- 日历内部已有事件拖拽完成触发
eventDrop回调时,回调参数自带revert()方法,调用后事件会直接回到拖拽前的原始位置,自动还原时间、所属资源等所有属性 - 外部元素拖入日历生成新事件触发
eventReceive回调时,拿到的临时事件对象自带remove()方法,调用后会直接删除刚拖入的未确认事件 - 事件缩放调整大小触发
eventResize回调时,参数同样自带revert()方法,回退逻辑和拖拽完全一致
具体实现步骤
- 新增ref存储拖拽临时数据和日历实例,避免无关重渲染
// 组件内新增 const calendarRef = useRef(null); const draggedEventRef = useRef(null);
给FullCalendar组件绑定ref:
<FullCalendar ref={calendarRef} // 其余原有配置不变 />
- 改造拖拽相关回调,暂存拖拽信息、触发确认弹窗
<FullCalendar // 原有配置不变 // 拖拽开始时暂存原始事件信息(做额外校验时可以用) eventDragStart={(e) => { draggedEventRef.current = { id: e.event.id, oldStart: e.event.start, oldEnd: e.event.end, oldResourceId: e.event.getResources()[0]?.id } }} // 内部事件拖拽完成 eventDrop={(drop) => { // 弹出确认框 setShowModal(true); // 暂存回调和新位置信息,等用户操作 draggedEventRef.current = { ...draggedEventRef.current, dropInfo: drop, newStart: drop.event.start, newEnd: drop.event.end, newResourceId: drop.event.getResources()[0]?.id, type: 'inner' } }} // 外部事件拖入日历 eventReceive={(e) => { setShowModal(true); draggedEventRef.current = { event: e.event, type: 'external' } }} // 事件缩放调整大小 eventResize={(resize) => { setShowModal(true); draggedEventRef.current = { resizeInfo: resize, type: 'resize' } }} />
- 编写弹窗确认/取消的处理逻辑
// 确认拖拽/缩放 const handleConfirmChange = () => { const current = draggedEventRef.current; if (current.type === 'inner') { // 内部事件移动:更新本地状态 setTableState(prev => prev.map(item => { if (item.id === current.id) { return { ...item, start: current.newStart, end: current.newEnd, resourceId: current.newResourceId } } return item })) // 这里可调用后端接口同步更新 } else if (current.type === 'external') { // 外部事件拖入:新增到本地状态 const newEvent = { id: Date.now(), // 生成正式业务id title: current.event.title, start: current.event.start, end: current.event.end, resourceId: current.event.getResources()[0]?.id } setTableState(prev => [...prev, newEvent]) // 移除临时渲染的外部事件 current.event.remove(); // 这里可调用后端接口新增事件 } else if (current.type === 'resize') { // 缩放逻辑和内部拖拽类似,更新对应事件的start/end即可 const resizeEvent = current.resizeInfo.event; setTableState(prev => prev.map(item => { if (item.id === resizeEvent.id) { return { ...item, start: resizeEvent.start, end: resizeEvent.end } } return item })) } setShowModal(false); } // 取消拖拽/缩放 const handleCancelChange = () => { const current = draggedEventRef.current; if (current.type === 'inner') { // 调用内置方法直接回退位置 current.dropInfo.revert(); } else if (current.type === 'external') { // 删除临时拖入的事件 current.event.remove(); } else if (current.type === 'resize') { // 缩放回退同样用内置revert current.resizeInfo.revert(); } setShowModal(false); }
- 将两个处理函数绑定到你的AlertBox组件的确认、取消按钮事件上即可。
注意事项
- 不要在
eventDrop/eventReceive/eventResize回调触发时立刻更新tableState,否则会和内置回退逻辑冲突导致位置错乱,等用户确认后再更新状态 - 拖拽过程中的临时数据全部存在
useRef中即可,不需要存到state,避免日历组件不必要的重渲染 - 该方案兼容FullCalendar v5、v6版本,不需要额外引入插件
内容的提问来源于stack exchange,提问作者Bilal Ashraf
相关产品推荐
相关产品推荐

