You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 05:39:14