如何阻止Blazor页面重载并保留html标签的data-bs-theme属性
解决.NET 8 Blazor Web App中Bootstrap主题路由切换后丢失的问题
问题原因
当使用<NavLink>或<a>标签进行路由切换时,Blazor会重新生成DOM结构,根节点<html>的自定义属性(比如data-bs-theme)会被重置。而你原来的JS代码仅在页面刷新/首次加载时执行,路由切换时不会重新触发,导致主题属性丢失。
简单解决方案(适合新手)
步骤1:重构JS代码,封装成可调用的全局方法
把原来的自执行函数改成可复用的全局方法,同时保留页面加载时的初始化逻辑:
window.themeManager = { // 初始化主题 applyTheme: function() { let theme = localStorage.getItem('theme'); // 没有存储值时,跟随系统主题 if (!theme) { theme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; } document.documentElement.setAttribute('data-bs-theme', theme); }, // 切换主题的方法(保留切换功能) toggleTheme: function() { const currentTheme = document.documentElement.getAttribute('data-bs-theme'); const newTheme = currentTheme === 'dark' ? 'light' : 'dark'; document.documentElement.setAttribute('data-bs-theme', newTheme); localStorage.setItem('theme', newTheme); } }; // 页面首次加载时初始化主题 window.themeManager.applyTheme();
步骤2:在布局组件中监听渲染/导航事件,重新应用主题
因为所有页面都基于MainLayout渲染,我们可以在MainLayout.razor中,每次页面渲染完成后调用JS方法重新设置主题:
@inject IJSRuntime JSRuntime @inject NavigationManager NavManager @implements IDisposable <!-- 你的布局内容 --> @code { protected override async Task OnAfterRenderAsync(bool firstRender) { // 每次渲染完成都重新应用主题(包括路由切换后的渲染) await JSRuntime.InvokeVoidAsync("window.themeManager.applyTheme"); await base.OnAfterRenderAsync(firstRender); } // 监听导航事件,确保路由切换后立即触发主题应用 protected override void OnInitialized() { NavManager.LocationChanged += OnRouteChanged; } private async void OnRouteChanged(object? sender, LocationChangedEventArgs e) { await JSRuntime.InvokeVoidAsync("window.themeManager.applyTheme"); } public void Dispose() { NavManager.LocationChanged -= OnRouteChanged; } }
方案生效逻辑
- 路由切换时,Blazor会重新渲染
MainLayout,OnAfterRenderAsync触发后调用JS重新设置data-bs-theme属性 - 导航事件监听确保即使布局未重新渲染,路由切换后也会立即应用主题
- 主题状态存在
localStorage中,不会因为页面渲染丢失
额外说明
- 如果你之前尝试
OnAfterRenderAsync无效果,大概率是加了if(firstRender)判断,仅在首次渲染时执行,路由切换后不会触发 - 无需移除
InteractiveServer渲染模式,该方案兼容所有Blazor渲染模式
内容的提问来源于stack exchange,提问作者cam
相关产品推荐
相关产品推荐

