Blazor通过JSInterop调用FullCalendarInterop.init提示未定义报错
问题根因
报错Could not find 'FullCalendarInterop.init' ('FullCalendarInterop' was undefined)由三个问题共同导致:
- Blazor JS隔离使用ES Module规范加载独立js文件,你当前的js文件没有用
export关键字暴露对外方法,文件内声明的FullCalendarInterop只是模块内部局部变量,外部无法访问。 - 导入ES模块后调用方法时,不需要额外加
FullCalendarInterop.前缀,直接调用模块导出的方法名即可。 - js代码存在拼写错误:
lenght应为length,即使方法能找到,运行到这行也会抛异常。
修复步骤
1. 修改JS文件(InputCalendar.razor.js)
移除原有套壳的函数声明,直接用ES Module语法导出方法,同时修复拼写错误:
// 直接导出init方法,不需要额外定义FullCalendarInterop全局变量 export function init(options, dotNetReference) { var calendarEl = document.getElementById(options.id); var calendar = new window.FullCalendar.Calendar(calendarEl, { plugins: ['interaction', 'dayGrid', 'timeGrid', 'list'], isRTL: window.KTUtil.isRTL(), header: { left: 'prev,next today', center: 'title', right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek' }, height: 800, contentHeight: 750, aspectRatio: 3, views: { dayGridMonth: { buttonText: 'month' }, timeGridWeek: { buttonText: 'week' }, timeGridDay: { buttonText: 'day' }, listWeek: { buttonText: 'list' } }, defaultView: options.defaultView, defaultDate: options.defaultDate, editable: true, eventLimit: true, navLinks: true, events: options.calendarEvents, eventRender: function (info) { var event = $(info.event); var element = $(info.el); var view = $(info.view); if (info.event.extendedProps && info.event.extendedProps.description) { if (element.hasClass('fc-day-grid-event')) { element.data('content', info.event.extendedProps.description); element.data('placement', 'top'); window.KTApp.initPopover(element); } else if (element.hasClass('fc-time-grid-event')) { element.find('.fc-title').append('<div class="fc-description">' + info.event.extendedProps.description + '</div>'); // 修复拼写错误:lenght -> length } else if (element.find('.fc-list-item-title').length !== 0) { element.find('.fc-list-item-title').append('<div class="fc-description">' + info.event.extendedProps.description + '</div>'); } } element.find(".fc-bg").css("pointer-events", "none"); element.find(".fc-list-item-title.fc-widget-content").prepend( "<span style='position: absolute; right: 5px;'>" + "<button class='btn btn-icon btn-xs btn-circle btn-light' " + "style='height: 16px; width: 16px;' id='calendar_del_" + event.id + "'>" + "<i class='icon-xs text-dark-50 flaticon2-cross'></i></button></span>"); element.find(".fc-content").append("<span style='position: absolute; top: 5px; right: 5px;'>" + "<button class='btn btn-icon btn-xs btn-circle btn-light' " + "style='height: 16px; width: 16px;' id='calendar_del_" + event.id + "'>" + "<i class='icon-xs text-dark-50 flaticon2-cross'></i></button></span>"); element.find("#calendar_del_" + event.id).click(function () { var eventIdentifier = event[0]._def.extendedProps.identifier; removeContent(".popover.fade.show.bs-popover-top"); dotNetReference.invokeMethodAsync('CalendarEventDeleted', eventIdentifier); }); }, viewSkeletonRender: function (info) { var view = $(info.view); var defaultView = view[0].type !== null ? view[0].type : ""; dotNetReference.invokeMethodAsync('SetDefaultView', defaultView); } }); calendar.render(); }
2. 修改Razor组件调用逻辑
调整方法调用路径,增加首次渲染判断和资源释放逻辑,避免重复初始化和内存泄漏:
@using Microsoft.JSInterop @inject IJSRuntime JSRuntime private IJSObjectReference? _fullCalendarModule; protected override async Task OnAfterRenderAsync(bool firstRender) { // 仅在首次渲染时初始化日历,避免重复创建实例 if (firstRender) { var options = new CalendarOptions { Id = Id, DefaultView = View, CalendarEvents = Events.Where(r => r.Status == CalendarEventStatus.Active).ToList() }; var dotNetObjectReference = DotNetObjectReference.Create(this); _fullCalendarModule = await JSRuntime.InvokeAsync<IJSObjectReference>("import", "./Shared/InputCalendar.razor.js"); // 直接调用模块导出的init方法即可 await _fullCalendarModule.InvokeVoidAsync("init", options, dotNetObjectReference); } await base.OnAfterRenderAsync(firstRender); } // 组件销毁时释放JS对象引用,避免内存泄漏 public async ValueTask DisposeAsync() { if (_fullCalendarModule != null) { await _fullCalendarModule.DisposeAsync(); } }
额外校验项
- 确认FullCalendar、KTUtil、KTApp、jQuery这些依赖的全局JS资源,已经在
index.html中提前引入,且路径正确,否则init方法执行时会报对象不存在错误。 - 确认
InputCalendar.razor.js文件的生成操作设置为「内容」,复制到输出目录属性设置为「如果较新则复制」,否则发布时文件不会被打包到对应路径,导致模块导入失败。
内容的提问来源于stack exchange,提问作者user2382627
相关产品推荐
相关产品推荐

