如何在Blazor中结合Bootstrap正确实现深色主题切换?
解决Blazor中Bootstrap主题切换后页面跳转丢失的问题
问题根源
你使用InteractiveAuto渲染模式时,切换到服务器端渲染(SSR)的页面时,服务器无法读取客户端localStorage中的主题设置,生成的<html>元素没有data-bs-theme属性,因此默认显示浅色主题;而刷新页面时客户端自执行JS会读取localStorage并设置主题,所以又恢复深色。
解决方案
1. 修改JavaScript代码,同步主题到Cookie
服务器无法读取localStorage但可以读取Cookie,因此需要把主题同时存入localStorage和Cookie:
function setTheme(theme) { localStorage.setItem('theme', theme); // 设置Cookie,有效期1年,确保全站可访问 document.cookie = `theme=${theme}; path=/; max-age=31536000; SameSite=Lax`; document.documentElement.setAttribute('data-bs-theme', theme); } function getTheme() { // 优先从localStorage取,没有则从Cookie解析 let theme = localStorage.getItem('theme'); if (!theme) { const cookies = document.cookie.split(';').map(c => c.trim()); const themeCookie = cookies.find(c => c.startsWith('theme=')); theme = themeCookie ? themeCookie.split('=')[1] : 'light'; } return theme; } // 初始加载时应用主题 (function() { const theme = getTheme(); setTheme(theme); })();
2. 服务器端渲染时设置<html>主题属性
在根布局文件(如_Layout.cshtml)中,读取Cookie并为<html>元素设置data-bs-theme属性:
<!DOCTYPE html> <html lang="zh-CN" data-bs-theme="@(Context.Request.Cookies["theme"] ?? "light")"> <head> <!-- 页面头部内容 --> </head> <body> @RenderBody() <!-- 加载你的JavaScript文件 --> </body> </html>
3. 优化Blazor组件的主题状态同步
修改组件代码,确保服务器端和客户端渲染时都能获取正确的主题值,避免切换按钮显示错误:
@rendermode InteractiveAuto @inject IJSRuntime Js @inject IHttpContextAccessor HttpContextAccessor <div class="nav-item px-3"> @if(_theme == "dark") { <a class="nav-link" @onclick='() => SetTheme("light")'> <Icon Class="px-3" Name=IconName.Moon />Light theme </a> } else { <a class="nav-link" @onclick='() => SetTheme("dark")'> <Icon Class="px-3" Name=IconName.Sun />Dark theme </a> } </div> @code { private string _theme = "light"; protected override async Task OnInitializedAsync() { if (OperatingSystem.IsBrowser()) { // 客户端环境:从JS获取主题 _theme = await Js.InvokeAsync<string>("getTheme"); } else { // 服务器端环境:从Cookie获取主题 _theme = HttpContextAccessor.HttpContext?.Request.Cookies["theme"] ?? "light"; } } private async Task SetTheme(string theme) { await Js.InvokeVoidAsync("setTheme", theme); _theme = theme; } }
额外配置
在Program.cs中注册IHttpContextAccessor服务:
builder.Services.AddHttpContextAccessor();
修改完成后,无论是服务器端渲染还是客户端渲染,主题都会保持一致,页面切换时不会出现主题丢失的问题。
内容的提问来源于stack exchange,提问作者Tomasz Sikora
相关产品推荐
相关产品推荐

