FullCalendar 3.8在EventAfterAllRender中设置minTime/maxTime导致循环渲染
解决FullCalendar中eventAfterAllRender设置minTime/maxTime导致的无限循环问题
兄弟,我之前也踩过FullCalendar这个无限渲染的坑!你的问题根源很明确:
当你在eventAfterAllRender回调里修改minTime或maxTime这类会改变日历视图时间范围的选项时,FullCalendar会自动触发重新渲染;而重新渲染完成后,又会再次调用eventAfterAllRender回调,这样就形成了无限循环,导致日历反复刷新。
下面给你几个可行的解决方案,按推荐程度排序:
方案1:添加状态标记,避免重复执行(兼容性最好)
给代码加一个全局标记变量,用来判断当前是否正在更新时间范围,避免回调重复触发AJAX和选项修改:
(function(c) { // 新增状态标记,防止循环执行 let isUpdatingTimeRange = false; var calendarOptions = { schedulerLicenseKey: '', header : { left : 'prevYear,prev today next,nextYear', center: 'title', right : 'month,agendaWeek,agendaDay' }, events : { url : '{{ url("calendar/events-json-calendar") }}', data: function () { return { id : $('#calendarsselect').val(), showDeleted: $('#showDeletedEvents').is(':checked'), }; } }, selectable : true, selectHelper : true, theme : false, slotDuration : '00:15:00', defaultView : 'agendaWeek', timeFormat : 'H:mm', slotLabelFormat : 'H:mm', editable : false, firstDay : 1, weekMode : 'liquid', weekNumbers : true, weekNumberTitle : "T: ", minTime : '06:00:00', maxTime : '20:00:00', locale : 'sk', scrollTime : '00:00', aspectRatio : 1.9, slotEventOverlap : false, droppable : true, lazyFetching : false, eventAfterAllRender : function (view, element) { // 如果正在更新时间范围,直接跳过本次回调 if (isUpdatingTimeRange) return; var date = moment(c.fullCalendar('getDate')).format('YYYY-MM-DD'); // 标记为正在更新 isUpdatingTimeRange = true; $.ajax({ url : '{{ url('calendar/worktime/get/minmaxtime') }}', dataType: "json", data : { calendar_id : $('#calendarsselect').val(), date : date }, success : function (data) { console.log(data); if ( data[0] != '23:59:59') { c.fullCalendar('option','minTime',data[0]); } if ( data[1] != '00:00:00') { c.fullCalendar('option','maxTime',data[1]); } // 更新完成,重置标记 isUpdatingTimeRange = false; }, // 出错时也要重置标记,避免后续无法触发更新 error: function() { isUpdatingTimeRange = false; } }); } }; c.fullCalendar(calendarOptions); })($('#calendar'));
原理
通过isUpdatingTimeRange标记,确保同一时间只有一次AJAX请求和选项修改操作。当修改minTime/maxTime触发重新渲染后,下次进入eventAfterAllRender时会因为标记为true直接跳过,从而打破循环。
方案2:切换到更早的回调函数(更简洁)
把逻辑从eventAfterAllRender移到viewRender回调中——这个回调只会在视图初始化或切换时触发一次,修改时间范围选项不会再次触发它,自然不会形成循环:
(function(c) { var calendarOptions = { // ... 其他选项保持不变 // 替换eventAfterAllRender为viewRender viewRender : function (view, element) { // 从view对象获取当前视图的起始日期,比getDate更准确 var date = moment(view.start).format('YYYY-MM-DD'); $.ajax({ url : '{{ url('calendar/worktime/get/minmaxtime') }}', dataType: "json", data : { calendar_id : $('#calendarsselect').val(), date : date }, success : function (data) { console.log(data); if ( data[0] != '23:59:59') { c.fullCalendar('option','minTime',data[0]); } if ( data[1] != '00:00:00') { c.fullCalendar('option','maxTime',data[1]); } } }); } }; c.fullCalendar(calendarOptions); })($('#calendar'));
注意事项
如果你的FullCalendar版本较新(v5+),viewRender已被废弃,需要改用datesRender或viewDidMount回调,逻辑是一样的。
方案3:提前获取时间范围再初始化日历(最彻底)
先通过AJAX获取初始日期的minTime/maxTime,再用这些值初始化日历,从根源避免初始化时的循环问题;同时在视图切换时再更新时间范围:
(function(c) { // 获取初始日期和日历ID var initialDate = moment().format('YYYY-MM-DD'); var calendarId = $('#calendarsselect').val(); // 先请求时间范围 $.ajax({ url : '{{ url('calendar/worktime/get/minmaxtime') }}', dataType: "json", data : { calendar_id : calendarId, date : initialDate }, success : function (data) { // 确定初始的minTime和maxTime var minTime = data[0] != '23:59:59' ? data[0] : '06:00:00'; var maxTime = data[1] != '00:00:00' ? data[1] : '20:00:00'; // 初始化日历 var calendarOptions = { // ... 其他选项保持不变 minTime : minTime, maxTime : maxTime, // 视图切换时更新时间范围 viewRender : function (view, element) { var date = moment(view.start).format('YYYY-MM-DD'); $.ajax({ url : '{{ url('calendar/worktime/get/minmaxtime') }}', dataType: "json", data : { calendar_id : $('#calendarsselect').val(), date : date }, success : function (data) { if ( data[0] != '23:59:59') { c.fullCalendar('option','minTime',data[0]); } if ( data[1] != '00:00:00') { c.fullCalendar('option','maxTime',data[1]); } } }); } }; c.fullCalendar(calendarOptions); } }); })($('#calendar'));
优势
这种方式完全避免了初始化阶段的循环问题,同时也能处理视图切换时的时间范围更新,逻辑最清晰。
内容的提问来源于stack exchange,提问作者Michal D
相关产品推荐
相关产品推荐

