目前在引用 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")
}
});
}



发表评论