如何让fullCalendar Scheduler按拖拽位置渲染事件而非固定在末尾
解决fullCalendar Scheduler拖拽外部事件到已有事件之间的渲染问题
我之前在用fullCalendar Scheduler做拖拽功能时,也碰到过一模一样的问题——外部事件拖过去后总跑到日历末尾,没法精准插入到两个已有事件之间。核心问题其实是drop回调里没正确计算新事件的时间位置,也没利用好日历按时间排序渲染事件的逻辑。
你可以试试这样修改你的drop代码:
drop: function(date, jsEvent, ui, resourceId) { console.log("dropped"); // 先拿到拖拽的外部事件基础数据 const draggedEventEl = $(ui.draggable); const eventTitle = draggedEventEl.text(); const eventId = draggedEventEl.attr('id'); // 获取当前日历实例,方便后续操作 const calendar = $('#your-calendar-id').fullCalendar('getCalendar'); // 筛选出当前资源下的所有已有事件 const targetResourceEvents = calendar.getEvents().filter(evt => evt.resourceId === resourceId); // 把已有事件按开始时间升序排序,方便找到插入位置 targetResourceEvents.sort((a, b) => a.start.unix() - b.start.unix()); // 确定新事件应该插入的位置索引 let insertIndex = targetResourceEvents.length; // 默认插在最后 for (let i = 0; i < targetResourceEvents.length; i++) { const currentEvt = targetResourceEvents[i]; // 如果拖拽时间点在当前事件之前,插在当前事件前面 if (date.isBefore(currentEvt.start)) { insertIndex = i; break; } // 如果拖拽时间点在当前事件和下一个事件之间,插在中间 if (i < targetResourceEvents.length - 1) { const nextEvt = targetResourceEvents[i+1]; if (date.isAfter(currentEvt.end) && date.isBefore(nextEvt.start)) { insertIndex = i + 1; break; } } } // 定义新事件的时长(你可以根据需求调整,比如从外部事件取预设时长) const eventDuration = moment.duration(1, 'hour'); let eventStart = date.clone(); let eventEnd = date.clone().add(eventDuration); // 处理和前后事件的重叠问题(如果不允许重叠的话) if (insertIndex > 0) { const prevEvt = targetResourceEvents[insertIndex - 1]; if (eventStart.isBefore(prevEvt.end)) { eventStart = prevEvt.end.clone(); eventEnd = eventStart.clone().add(eventDuration); } } if (insertIndex < targetResourceEvents.length) { const nextEvt = targetResourceEvents[insertIndex]; if (eventEnd.isAfter(nextEvt.start)) { eventEnd = nextEvt.start.clone(); eventStart = eventEnd.clone().subtract(eventDuration); } } // 添加新事件到日历 calendar.addEvent({ id: eventId, title: eventTitle, start: eventStart, end: eventEnd, resourceId: resourceId, className: draggedEventEl.attr('class') // 继承原事件的样式 }); // 可选:拖拽完成后移除页面上的原外部事件元素 draggedEventEl.remove(); }
关键注意点:
- 获取并排序目标资源的事件:只有把已有事件按时间排序,才能准确找到新事件的插入位置,保证渲染顺序正确。
- 精准计算事件的起止时间:fullCalendar的资源视图是按事件的
start时间自动排序渲染的,只要新事件的start时间落在两个已有事件的时间区间内,就会自动显示在中间位置。如果允许事件重叠,可以去掉重叠检查的代码块。 - 确保日历配置正确:别忘了在日历初始化时开启
droppable: true,并设置dropAccept指定可拖拽的元素类名,比如:
$('#your-calendar-id').fullCalendar({ schedulerLicenseKey: 'GPL-My-Project-Is-Open-Source', resources: [/* 你的资源数据 */], defaultView: 'timelineResourceDay', // 或者你使用的其他资源视图 editable: true, droppable: true, dropAccept: '.fc-event', // 其他配置项... });
这样调整后,拖拽外部事件到两个已有事件之间时,新事件就会显示在对应的位置,而不是默认跑到末尾啦。
内容的提问来源于stack exchange,提问作者Jack1999
相关产品推荐
相关产品推荐

