阿毛
It's me !
想你所想

fullcalendar render无效问题

https://file.blog.humh.cn/wp-content/uploads/2025/09/20250909184351170-300x262.png

目前在引用 fullcalendar@5.11.3 时
<link href="https://cdn.jsdelivr.net/npm/fullcalendar@5.11.3/main.min.css" rel="stylesheet">

遇到了重新刷新渲染调用 render 函数无效的问题。

业务场景

https://file.blog.humh.cn/wp-content/uploads/2025/09/20250909185051846-298x300.png

希望点击或滑动选中一个或多个日期后,日历控件上能立马背景加深标记。

问题发现

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 版本时就已经去掉了

https://file.blog.humh.cn/wp-content/uploads/2025/09/20250909190500622-1024x64.png

销毁重新创建 calendar 的话,有性能问题且可能带来其他问题

其实可以换个思路,最终背景色变更无非就是增加 css 的支持,css 本身控件已提供,只需给需要背景色的日期 html 块增加该 css 样式即可。

https://file.blog.humh.cn/wp-content/uploads/2025/09/20250910163200370-1024x647.png
17号背景色标记对应html片段

对于 click 事件,官方提供了直接调整 html 的入口

https://file.blog.humh.cn/wp-content/uploads/2025/09/20250910163435506-1024x481.png
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")
        }
    });
}

humh

文章作者

站长本人,一个憨批!

发表评论

textsms
account_circle
email

想你所想

fullcalendar render无效问题
目前在引用 fullcalendar@5.11.3 时<link href="https://cdn.jsdelivr.net/npm/fullcalendar@5.11.3/main.min.css" rel="stylesheet"> 遇到了重新刷新渲染调用 render 函数无效的问…
扫描二维码继续阅读
2025-09-10