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

Blazor页面未完成渲染前导航触发JSInterop异常问题排查

Blazor未完成图表渲染时导航抛出JS异常的解决方案

当页面触发导航时,当前组件会被立即销毁,但OnAfterRenderAsync中正在执行的Blazor Bootstrap图表初始化JS互操作仍在尝试访问已被移除的DOM元素,从而抛出Cannot read properties of null (reading 'id')异常。以下是无需等待渲染完成即可安全导航的解决方案:

方案1:用取消令牌终止未完成的JS操作

在图表组件中引入CancellationTokenSource,在组件销毁时取消未完成的初始化任务,避免无效的DOM访问:

@implements IDisposable

<BlazorBootstrap.DoughnutChart @ref="CurrentDonut" />

@code {
    [Inject] private NavigationManager NavManager { get; set; } = default!;
    private DoughnutChart? CurrentDonut;
    private CancellationTokenSource? _cts;

    protected override void OnInitialized()
    {
        _cts = new CancellationTokenSource();
        // 配置图表数据与选项
        CurrentUsageData = /* 你的数据逻辑 */;
        CurrentUsageOptions = /* 你的选项配置 */;
        base.OnInitialized();
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender && _cts is not null && !_cts.Token.IsCancellationRequested)
        {
            try
            {
                // 传递取消令牌到图表初始化方法
                await CurrentDonut!.InitializeAsync(CurrentUsageData, CurrentUsageOptions, cancellationToken: _cts.Token);
            }
            catch (OperationCanceledException)
            {
                // 组件已销毁,静默忽略取消异常
            }
        }
        await base.OnAfterRenderAsync(firstRender);
    }

    public void Dispose()
    {
        // 取消未完成的异步任务
        _cts?.Cancel();
        _cts?.Dispose();
        // 清理图表实例(Blazor Bootstrap组件支持Dispose)
        CurrentDonut?.Dispose();
    }

    private ChartData CurrentUsageData = default!;
    private ChartOptions CurrentUsageOptions = default!;
}

方案2:给导航按钮添加状态控制

通过状态标记防止重复点击,同时在导航前锁定操作,避免无效的后续执行:

<button @onclick="Navigate" disabled="@_isNavigating">跳转到仪表盘</button>

@code {
    [Inject] private NavigationManager NavManager { get; set; } = default!;
    private bool _isNavigating;

    private void Navigate()
    {
        if (_isNavigating) return;
        _isNavigating = true;
        NavManager.NavigateTo("/Dashboard");
        // 导航后组件会立即销毁,无需重置_isNavigating
    }
}

方案3:监听导航事件跳过初始化

通过NavigationManager的导航事件标记组件状态,跳过后续的图表初始化逻辑:

@implements IDisposable

<BlazorBootstrap.DoughnutChart @ref="CurrentDonut" />

@code {
    [Inject] private NavigationManager NavManager { get; set; } = default!;
    private DoughnutChart? CurrentDonut;
    private bool _hasNavigated;

    protected override void OnInitialized()
    {
        NavManager.LocationChanged += OnLocationChanged;
        // 配置图表数据与选项
        CurrentUsageData = /* 你的数据逻辑 */;
        CurrentUsageOptions = /* 你的选项配置 */;
        base.OnInitialized();
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender && !_hasNavigated)
        {
            try
            {
                await CurrentDonut!.InitializeAsync(CurrentUsageData, CurrentUsageOptions);
            }
            catch (JSException)
            {
                // 捕获DOM不存在的异常,静默处理
            }
        }
        await base.OnAfterRenderAsync(firstRender);
    }

    private void OnLocationChanged(object? sender, LocationChangedEventArgs e)
    {
        _hasNavigated = true;
    }

    public void Dispose()
    {
        NavManager.LocationChanged -= OnLocationChanged;
        CurrentDonut?.Dispose();
    }

    private ChartData CurrentUsageData = default!;
    private ChartOptions CurrentUsageOptions = default!;
}

以上方案均无需等待所有组件渲染完成即可安全导航,同时避免了forceReload参数导致的用户认证丢失问题。

内容的提问来源于stack exchange,提问作者donny_V

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 20:13:11