目前在引用 fullcalendar@5.11.3 时<link href="https://cdn.jsdelivr.net/npm/fullcalendar@5.11.3/main.min.css" rel="stylesheet">
遇到了重新刷新渲染调用 render 函数无效的问题。
业务场景
希望点击或滑动选中一个或多个日期后,日历控件上能立马背景加深标记。
问题发现
function initFullCalendar() { var calendarEl = document.getElementById('calendar'); if (!calendarEl) return; // 如果已经初始化过,则销毁重新初始化 if (calendar) { calendar.destroy(); } calendar = new FullCalendar.Calendar(calendarEl, { initialView: 'dayGridMonth', selectable: true, selectMirror: true, dayCellClassNames: function(arg) { // 检查日期是否已被选中 var dateStr = formatDate(arg.date); if (selectedDates.includes(dateStr)) { return ['selected']; } return []; }, dateClick: function(info) { // 单击选择日期 toggleDateSelection(info.dateStr); }, select: function(info) { // 范围选择 var start = new Date(info.start); var end = new Date(info.end); console.log(start, " ~ ",end) // 逐日添加到选中列表 var currentDate = new Date(start); while (currentDate < end) { var dateStr = formatDate(currentDate); console.log(dateStr) if (!selectedDates.includes(dateStr)) { selectedDates.push(dateStr); } currentDate.setDate(currentDate.getDate() + 1); } updateSelectedDatesDisplay(selectedDates); calendar.render(); // 重新渲染以更新样式 } }); calendar.render(); document.getElementById("clear-selected-dates-btn").addEventListener("click", function() { // 清空 selectedDates 数组 selectedDates.length = 0; // 更新显示 updateSelectedDatesDisplay(selectedDates); // 重新渲染日历以更新选中状态 if (calendar) { calendar.render(); } alert("已清空所有选中的日期"); }); } // 正确格式化日期,避免时区问题 function formatDate(date) { var year = date.getFullYear(); var month = (date.getMonth() + 1).toString().padStart(2, '0'); var day = date.getDate().toString().padStart(2, '0'); return year + '-' + month + '-' + day; } // 切换日期选中状态 function toggleDateSelection(dateStr) { var index = selectedDates.indexOf(dateStr); if (index < 0) { // 如果未选中,则添加到选中列表 selectedDates.push(dateStr); } updateSelectedDatesDisplay(selectedDates); calendar.render(); // 重新渲染以更新样式 } function updateSelectedDatesDisplay(dates) { var displayDiv = document.getElementById("selected-dates-display"); if (!displayDiv) return; // 对日期数组进行升序排序 dates.sort(function(a, b) { return new Date(a) - new Date(b); }); var html = '<div style="margin-top: 10px;"><strong>已选日期:</strong><ul>'; dates.forEach(function(date) { html += '<li style="list-style: disc; margin-left: 20px;">' + date + ' <a href="#" onclick="removeDate(\'' + date + '\'); return false;" style="color:red; text-decoration: none;">[x]</a></li>'; }); html += '</ul></div>'; displayDiv.innerHTML = html; } function removeDate(date) { var index = selectedDates.indexOf(date); if (index > -1) { selectedDates.splice(index, 1); updateSelectedDatesDisplay(selectedDates); calendar.render(); // 重新渲染以更新样式 } }
原先代码如上,重点在于每次已选日期更新后,会通过调用 render() 函数来更新。但实测发现,只有在点击日历控件右上角的“<”(上个月)与“>”(下个月)切换刷新后,才会背景色变更标记。
官方查到确有这个 BUG,其中有人反馈调用 rerenderEvents 函数实现,但这个 V4 到 V5 版本时就已经去掉了

销毁重新创建 calendar 的话,有性能问题且可能带来其他问题
其实可以换个思路,最终背景色变更无非就是增加 css 的支持,css 本身控件已提供,只需给需要背景色的日期 html 块增加该 css 样式即可。
对于 click 事件,官方提供了直接调整 html 的入口

dateClick: function(info) { // 单击选择/取消选择日期 toggleDateSelectionAndVisual(info.dateStr, info.dayEl); } function toggleDateSelectionAndVisual(dateStr, dayEl) { var index = selectedDates.indexOf(dateStr); if (index < 0) { selectedDates.push(dateStr); // 添加视觉效果 dayEl.classList.add('selected'); } else { // 如果已选中,则从列表中移除 selectedDates.splice(index, 1); // 移除视觉效果 dayEl.classList.remove('selected'); } updateSelectedDatesDisplay(selectedDates); }
可惜对于 select 时间未提供类似入口,同时个人代码中日期变更最终都会走到 updateSelectedDatesDisplay 函数中,在这里增加渲染的代码是最方便的。所以不依赖官方口子,不依赖官方函数的方式就是自己改 html
找到对应控件的div块元素(我这里是 regular-date-picker),遍历dates,每次遍历元素变量为date,每次给其下class中包含“ fc-day”且有 data-date同时 data-date 值 date 为子div (并非第一层子div,可能下面好几层),class中增加“selected”
function updateSelectedDatesDisplay(dates) { var displayDiv = document.getElementById("selected-dates-display"); if (!displayDiv) return; // 对日期数组进行升序排序 dates.sort(function(a, b) { return new Date(a) - new Date(b); }); updateCalendarDateSelection(dates); var html = '<div style="margin-top: 10px;"><strong>已选日期:</strong><ul>'; dates.forEach(function(date) { html += '<li style="list-style: disc; margin-left: 20px;">' + date + ' <a href="#" onclick="removeDate(\'' + date + '\'); return false;" style="color:red; text-decoration: none;">[x]</a></li>'; }); html += '</ul></div>'; displayDiv.innerHTML = html; } // 渲染日历以更新选中状态 calendar.render()无法刷新有bug function updateCalendarDateSelection(dates) { // 找到日历容器 var calendarContainer = document.getElementById("regular-date-picker"); if (!calendarContainer) return; // 先移除所有已存在的selected类 var allSelectedDays = calendarContainer.querySelectorAll('.fc-day.selected'); console.log(allSelectedDays, allSelectedDays) allSelectedDays.forEach(function(dayElement) { dayElement.classList.remove('selected'); }); // 为每个选中的日期添加selected类 dates.forEach(function(date) { // 查找匹配的日期元素 var dayElement = calendarContainer.querySelector('.fc-day[data-date="' + date + '"]'); if (dayElement) { dayElement.classList.add('selected'); console.log(dayElement, "selected") } }); }
发表评论