Bootstrap标签页点击时销毁FullCalendar避免重复初始化问题
解决FullCalendar在Bootstrap标签页重复创建及销毁报错问题
问题分析
你遇到的两个核心问题:
- 重复创建日历叠加显示:每次点击标签页都会调用
calendar_view_session函数,每次都新建一个FullCalendar实例,没有清理旧实例。 - 销毁方法报错:
$("#calendar").destroy()是错误用法——FullCalendar v4及以上版本是原生JavaScript库,不是jQuery插件,destroy方法属于Calendar实例本身,而非jQuery元素的方法,直接调用jQuery对象的destroy会抛出类型错误。
解决方案
我们可以通过保存日历实例引用+利用Bootstrap标签页的显示事件来解决这两个问题,同时优化性能。
方案1:销毁旧实例后重建(适合需要动态更新配置的场景)
- 在app对象中添加实例存储属性:用来保存当前的Calendar实例,方便后续销毁。
- 修改
calendar_view_session函数:先检查是否存在旧实例,存在则销毁,再创建新实例。 - 替换点击事件为Bootstrap标签页的
shown.bs.tab事件:避免重复点击触发多次初始化,同时确保日历在元素显示后再渲染(解决隐藏元素渲染尺寸异常问题)。
修改后的代码如下:
JavaScript部分
// 在app对象初始化时添加实例存储属性 app.calendarInstance = null; calendar_view_session: function(){ // 销毁已存在的日历实例 if (app.calendarInstance) { app.calendarInstance.destroy(); app.calendarInstance = null; } var calendarEl = document.getElementById('calendar'); var calendar = new FullCalendar.Calendar(calendarEl, { plugins: [ 'dayGrid', 'timeGrid', 'list', 'interaction' , 'momentTimezone' ], header: { left: 'prev,next today', center: 'title', right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek' }, defaultDate: '2019-04-12', navLinks: true, editable: false, eventLimit: true, events: function(info, successCallback,failureCallback) { var date1 = new Date(info.start.valueOf()); var date2 = new Date(info.end.valueOf()); var callData = { from_date:moment.tz(date1, timeZone).format('YYYY-MM-DD'), to_date: moment.tz(date2, timeZone).format('YYYY-MM-DD') } sessionCalendar = []; $.ajax({ url:app.createApiPath(apiController_data,apiAction_data), method:"POST", dataType: "json", data: { callData: JSON.parse(JSON.stringify(callData)), api_version: 1, deviceType: 'web' }, success: function(responseData){ successCallback(app.calendarParse(responseData.data.results)); } }) }, }); calendar.render(); // 保存实例到app对象,方便后续销毁 app.calendarInstance = calendar; }, // 监听Bootstrap标签页显示事件 $(document).ready(function() { $('#calendar_view_session_id').on('shown.bs.tab', function () { app.calendar_view_session(); }); });
HTML部分(移除onclick事件)
<div> <!-- Nav tabs --> <ul class="nav nav-tabs" role="tablist"> <li role="presentation" class="active"><a href="#list_view_session" aria-controls="list_view_session" role="tab" data-toggle="tab">List View</a></li> <li role="presentation"><a href="#calendar_view_session" id="calendar_view_session_id" aria-controls="calendar_view_session" role="tab" data-toggle="tab">Calendar View</a></li> </ul> <!-- Tab panes --> <div class="tab-content"> <div role="tabpanel" class="tab-pane active" id="list_view_session"> <div class="session_list"> <div class="loaderapi hide"> <i class="fa fa-spinner fa-spin fa-4x" aria-hidden="true"></i> </div> </div> </div> <div role="tabpanel" class="tab-pane" id="calendar_view_session"> <div id='calendar'></div> </div> </div> </div>
方案2:仅初始化一次,显示时更新尺寸(性能更优)
如果你的日历配置不需要动态修改,推荐这种方式——只初始化一次日历,每次标签页显示时更新尺寸即可,避免重复销毁重建:
// 全局或app对象中存储日历实例 app.calendarInstance = null; $(document).ready(function() { // 初始化日历(但不立即渲染,因为元素处于隐藏状态) var calendarEl = document.getElementById('calendar'); app.calendarInstance = new FullCalendar.Calendar(calendarEl, { // 你的日历配置... }); // 监听标签页显示事件 $('#calendar_view_session_id').on('shown.bs.tab', function () { // 第一次显示时渲染日历,之后每次显示更新尺寸 if (!app.calendarInstance.rendered) { app.calendarInstance.render(); } else { app.calendarInstance.updateSize(); } }); });
关键说明
- FullCalendar实例的销毁:必须调用Calendar实例的
destroy()方法,而非jQuery元素的方法,这是v4+版本的重要变化(之前的jQuery版本是$('#calendar').fullCalendar('destroy'))。 - Bootstrap标签页事件:使用
shown.bs.tab而非show.bs.tab,确保标签页完全显示后再操作日历,避免因元素隐藏导致的渲染尺寸异常。
内容的提问来源于stack exchange,提问作者Santosh
相关产品推荐
相关产品推荐

