Fullcalendar异步加载事件场景下如何按日聚合多事件扩展属性值
异步加载事件场景下日期单元格事件属性聚合方案
针对事件异步加载、单元格渲染早于事件返回导致的渲染钩子无法直接统计的问题,不需要全量重渲染整个日历,按以下三步实现即可,性能开销远低于全量重绘:
- 单元格首次渲染阶段预留统计位
触发day cell content钩子时,不直接读取内存中的事件做计算,给每个日期单元格挂载固定格式的日期标识(比如data-date属性存YYYY-MM-DD格式的日期字符串),同时在单元格内预留专门的统计值展示节点,初始状态可展示加载占位符。 - 事件加载完成后做日期维度聚合
等异步事件全部加载、渲染完成后(可以用日历组件自带的加载完成回调,比如加载状态从true变false的钩子、批量事件挂载完成的钩子),遍历当前已加载的所有事件,按事件开始日期分组,累加需要统计的扩展属性值,生成「日期字符串: 聚合结果」的映射表。 - 定向更新单元格统计值
拿到聚合映射表后,通过DOM选择器匹配对应日期标识的单元格,直接更新预留统计节点的内容即可,不需要走日历组件的重渲染流程。没有匹配到事件的日期,直接把统计占位符更新为0。
参考实现代码(基于Vue + FullCalendar,原生JS逻辑一致)
单元格渲染钩子配置:
dayCellContent: (arg) => { const dateStr = moment(arg.date).format('YYYY-MM-DD') const cellContainer = document.createElement('div') // 给容器加日期标识,方便后续定向查找 cellContainer.dataset.date = dateStr // 预留统计值节点 const statTag = document.createElement('span') statTag.className = 'daily-event-sum' statTag.innerText = '…' cellContainer.appendChild(statTag) return { domNodes: [cellContainer] } }
事件加载完成后的聚合更新逻辑:
// 绑定到日历的loading回调,loading为false代表事件加载完成 handleCalendarLoading(isLoading) { if (isLoading) return const calendarApi = this.$refs.calendar.getApi() // 取当前视图范围内的事件,不需要取全量 const viewEvents = calendarApi.getEvents() const dateSumMap = {} // 按日期聚合扩展属性,示例统计extendedProps.count字段的总和 viewEvents.forEach(event => { const eventDate = moment(event.start).format('YYYY-MM-DD') dateSumMap[eventDate] = (dateSumMap[eventDate] || 0) + Number(event.extendedProps.count || 0) }) // 定向更新有事件的日期统计值 Object.entries(dateSumMap).forEach(([dateStr, sumVal]) => { const statNode = document.querySelector(`[data-date="${dateStr}"] .daily-event-sum`) if (statNode) statNode.innerText = sumVal }) // 把无事件日期的占位符更新为0 document.querySelectorAll('.daily-event-sum').forEach(node => { if (node.innerText === '…') node.innerText = 0 }) }
注意:如果是分段加载事件(比如切换月/周视图仅加载当前视图时间范围的事件),只需要在每次加载完成后重复执行上述聚合更新逻辑即可,不需要修改单元格初始渲染逻辑。该方案完全解耦单元格渲染和事件加载的时序,既不需要修改组件源码让渲染钩子入参携带当日事件,也不会产生全量重渲染的性能损耗。
内容的提问来源于stack exchange,提问作者karns
相关产品推荐
相关产品推荐

