React FullCalendar:支持用户通过拖拽调整日历事件的上下排序
实现FullCalendar DayGridMonth视图内事件拖拽排序
核心思路
通过FullCalendar的拖拽交互API,结合自定义排序逻辑,在拖拽结束后更新事件的优先级字段,重新排序并渲染对应日期的事件,实现单元格内直接拖拽调整顺序的效果。
1. 基础配置(启用拖拽)
初始化FullCalendar时开启编辑/拖拽功能,同时引入interaction插件支持拖拽交互:
document.addEventListener('DOMContentLoaded', function() { const calendarEl = document.getElementById('calendar'); const calendar = new FullCalendar.Calendar(calendarEl, { plugins: ['dayGrid', 'interaction'], initialView: 'dayGridMonth', editable: true, // 全局开启编辑拖拽 eventDragStop: handleEventReorder, // 绑定拖拽结束事件 events: [ // 示例事件:需包含start(日期)、priority(排序字段) { title: '任务A', start: '2024-05-20', priority: 1, id: 'evt1' }, { title: '任务B', start: '2024-05-20', priority: 2, id: 'evt2' } ] }); calendar.render(); });
2. 拖拽排序逻辑实现
定义拖拽结束后的处理函数,根据拖拽方向调整事件优先级,重新排序对应日期的事件:
function handleEventReorder(info) { const draggedEvent = info.event; const targetDate = draggedEvent.startStr; // 获取当前日期下的所有事件 const dayEvents = calendar.getEvents().filter(evt => evt.startStr === targetDate); const draggedIndex = dayEvents.findIndex(evt => evt.id === draggedEvent.id); let newPriority; // 根据拖拽方向计算新优先级(从上到下优先级数值递增) if (info.deltaY > 0) { // 向下拖拽:取后一个事件优先级+1,无后续则取当前最大优先级+1 const nextEvent = dayEvents[draggedIndex + 1]; newPriority = nextEvent ? nextEvent.extendedProps.priority + 1 : Math.max(...dayEvents.map(e => e.extendedProps.priority)) + 1; } else { // 向上拖拽:取前一个事件优先级-1,无前驱则取当前最小优先级-1 const prevEvent = dayEvents[draggedIndex - 1]; newPriority = prevEvent ? prevEvent.extendedProps.priority - 1 : Math.min(...dayEvents.map(e => e.extendedProps.priority)) - 1; } // 更新当前事件优先级 draggedEvent.setExtendedProp('priority', newPriority); // 重新排序并渲染当前日期的事件 dayEvents.sort((a, b) => a.extendedProps.priority - b.extendedProps.priority); calendar.removeEvents(evt => evt.startStr === targetDate); calendar.addEventSource(dayEvents); // 可选:将新的优先级数据提交到后端保存 // saveEventPriority(draggedEvent.id, newPriority); }
3. 初始渲染时按优先级排序
确保页面加载时,每个日期的事件默认按优先级排序展示:
// 对原始事件数据按日期分组后排序 function sortEventsByPriority(events) { const groupedByDate = {}; events.forEach(evt => { const date = evt.start; if (!groupedByDate[date]) groupedByDate[date] = []; groupedByDate[date].push(evt); }); // 每组按优先级升序排列 Object.values(groupedByDate).forEach(group => { group.sort((a, b) => a.priority - b.priority); }); // 扁平化后返回 return [].concat(...Object.values(groupedByDate)); } // 使用示例 const rawEvents = [/* 你的原始事件数组 */]; const sortedEvents = sortEventsByPriority(rawEvents); calendar.addEventSource(sortedEvents);
注意事项
- 如果需要支持跨日期拖拽,需在
handleEventReorder中额外处理事件的start字段更新逻辑。 - 若要持久化排序结果,在更新优先级后需调用后端接口保存最新的优先级数据。
- 可优化优先级计算逻辑,比如直接使用拖拽后的索引作为优先级(如索引0对应优先级1,索引1对应优先级2),避免出现数值间隙。
内容的提问来源于stack exchange,提问作者Josh Cox
相关产品推荐
相关产品推荐

