如何在FullCalendar中合并(折叠/展开)相似事件
嘿,我之前也在FullCalendar里折腾过这个折叠同标题重叠事件的需求,官方确实没直接提供这个功能,不过咱们可以自己动手实现!给你分享一个我试过可行的方案:
实现思路
核心是在所有事件渲染完成后,按标题分组并筛选出时间重叠的事件,然后给每组添加折叠/展开的触发控件,通过CSS和JS控制事件的显示隐藏,完美实现你要的折叠效果。
1. 核心代码实现
首先在FullCalendar的配置里,利用eventsRender钩子(所有事件渲染完成后触发)来处理分组和折叠逻辑:
document.addEventListener('DOMContentLoaded', function() { const calendarEl = document.getElementById('calendar'); const calendar = new FullCalendar.Calendar(calendarEl, { // 你的基础日历配置(比如视图、事件源等) initialView: 'dayGridMonth', events: [ // 示例事件数据,替换成你的实际数据 {id: '1', title: '重复会议', start: '2024-05-20T09:00:00', end: '2024-05-20T10:30:00'}, {id: '2', title: '重复会议', start: '2024-05-20T10:00:00', end: '2024-05-20T11:30:00'}, {id: '3', title: '单独任务', start: '2024-05-20T14:00:00', end: '2024-05-20T15:00:00'}, ], eventsRender: function(info) { // 1. 按事件标题分组 const eventGroups = {}; const eventEls = info.el.querySelectorAll('.fc-event'); eventEls.forEach(el => { const title = el.querySelector('.fc-event-title').textContent; const eventId = el.dataset.eventId; const event = calendar.getEventById(eventId); if (!eventGroups[title]) { eventGroups[title] = []; } eventGroups[title].push({ el, event }); }); // 2. 处理每个分组,筛选重叠事件并添加折叠功能 Object.values(eventGroups).forEach(group => { if (group.length <= 1) return; // 单个事件无需处理 // 筛选出当前分组中时间重叠的事件 const overlappingEvents = group.filter((item, index) => { if (index === 0) return true; const prevEvent = group[index-1].event; return isEventsOverlapping(item.event, prevEvent); }); if (overlappingEvents.length <= 1) return; // 给第一个事件添加折叠触发三角 const firstEventEl = overlappingEvents[0].el; const caret = document.createElement('span'); caret.className = 'fc-event-caret'; caret.textContent = '▼'; firstEventEl.appendChild(caret); // 默认隐藏组内其他重叠事件 overlappingEvents.slice(1).forEach(item => { item.el.classList.add('fc-event-hidden'); }); // 绑定点击事件切换展开/收起状态 caret.addEventListener('click', () => { const isExpanded = caret.textContent === '▼'; caret.textContent = isExpanded ? '▲' : '▼'; overlappingEvents.slice(1).forEach(item => { item.el.classList.toggle('fc-event-hidden'); }); }); }); } }); calendar.render(); }); // 辅助函数:判断两个事件是否时间重叠 function isEventsOverlapping(eventA, eventB) { return eventA.start < eventB.end && eventA.end > eventB.start; }
2. 配套CSS样式
添加以下CSS来控制隐藏状态和三角标记的样式:
/* 隐藏折叠的事件 */ .fc-event-hidden { display: none !important; } /* 折叠三角的样式 */ .fc-event-caret { float: right; cursor: pointer; font-size: 0.8em; margin-left: 6px; color: #666; }
3. 关键注意事项
- 如果你的事件是异步加载的(比如从接口获取),
eventsRender钩子依然能正常触发,因为它会在所有事件渲染完成后执行 - 重叠判断逻辑可以根据需求调整:比如你可以改成只合并完全重叠的事件,或者调整时间范围的判断规则
- 如果你用的是FullCalendar v5+,注意事件元素的类名可能略有变化(比如
.fc-event-main),需要对应修改代码中的选择器 - 可以进一步优化分组逻辑,比如只处理同一天内的同标题重叠事件,避免跨天事件被错误折叠
这个方案不会像你之前找到的案例那样把事件合并成一个,而是保留原事件的独立性,通过显示隐藏实现折叠/展开,完全符合你的需求!
内容的提问来源于stack exchange,提问作者zan_li
相关产品推荐
相关产品推荐

