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

Blazor Server+Bootstrap侧滑导航双击打开问题及解决困境

Blazor Server + Bootstrap Offcanvas 双击触发及后续问题解决

原问题:路由跳转后侧滑导航需双击打开

本质是Blazor Server静态渲染模式下,Bootstrap的Offcanvas JS初始化逻辑在路由跳转后没有重新绑定。首次点击时,Bootstrap仅完成了状态类的标记,但没触发弹窗的显示逻辑,第二次点击才会执行完整的打开流程。

你用@rendermode Interactive Server解决了双击问题,但引出两个新问题,下面是针对性的解决方法:


问题1:页面跳转后菜单不自动关闭

通过注入NavigationManager监听路由变化,手动关闭Offcanvas:

@inject NavigationManager NavManager
@implements IDisposable

<!-- 保留你的Offcanvas按钮和容器代码 -->
<button class="navbar-toggler" type="button" data-bs-toggle="offcanvas" data-bs-target="#offcanvasNav" aria-controls="offcanvasNav">
    <i class="bi bi-list"></i>
</button>

<div class="offcanvas offcanvas-start" tabindex="-1" id="offcanvasNav" aria-labelledby="offcanvasNavLabel" @ref="_offcanvas">
    <!-- Offcanvas内容不变 -->
</div>

@code {
    private Offcanvas? _offcanvas;

    protected override void OnInitialized()
    {
        NavManager.LocationChanged += OnRouteChanged;
    }

    private async void OnRouteChanged(object? sender, LocationChangedEventArgs e)
    {
        if (_offcanvas?.IsShown == true)
        {
            await _offcanvas.HideAsync();
        }
    }

    public void Dispose()
    {
        NavManager.LocationChanged -= OnRouteChanged;
    }
}

问题2:自定义激活链接功能失效

原代码里的路径判断只会在组件初始化时执行一次,路由变化后不会自动更新。需要监听路由变化事件,刷新当前路径并触发组件重渲染:

@inject NavigationManager NavManager
@implements IDisposable

<li class="admin-dropdown">
    <a class="admin-item dropdown-item @(IsActiveRoute("/Admin/Courses"))" href="/Admin/Courses">
        Edit Courses
        <i class="bi bi-chevron-right"></i>
    </a>
</li>

@code {
    private string _currentPath = string.Empty;

    protected override void OnInitialized()
    {
        _currentPath = GetCurrentRelativePath();
        NavManager.LocationChanged += OnRouteChanged;
    }

    private string GetCurrentRelativePath()
    {
        return new Uri(NavManager.Uri).AbsolutePath;
    }

    private bool IsActiveRoute(string route)
    {
        return _currentPath.Equals(route, StringComparison.OrdinalIgnoreCase);
    }

    private void OnRouteChanged(object? sender, LocationChangedEventArgs e)
    {
        _currentPath = GetCurrentRelativePath();
        StateHasChanged(); // 更新激活状态
    }

    public void Dispose()
    {
        NavManager.LocationChanged -= OnRouteChanged;
    }
}

替代方案:不启用Interactive Server解决双击问题

如果想保持静态渲染模式,也可以在组件渲染完成后手动初始化Bootstrap Offcanvas:

@inject IJSRuntime JSRuntime
@inject NavigationManager NavManager
@implements IDisposable

<!-- 你的Offcanvas代码 -->

@code {
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        await ReInitOffcanvas();
        if (firstRender)
        {
            NavManager.LocationChanged += async (s, e) => await ReInitOffcanvas();
        }
    }

    private async Task ReInitOffcanvas()
    {
        // 先销毁已有的实例,再重新初始化
        await JSRuntime.InvokeVoidAsync("(() => { const offcanvas = bootstrap.Offcanvas.getInstance('#offcanvasNav'); if(offcanvas) offcanvas.dispose(); new bootstrap.Offcanvas('#offcanvasNav'); })");
    }

    public void Dispose()
    {
        NavManager.LocationChanged -= async (s, e) => await ReInitOffcanvas();
    }
}

这种方式无需启用Interactive Server,直接通过JS重新初始化解决双击问题,也不会带来后续的菜单关闭和激活链接问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 18:33:10