Blazor实现主题切换的核心思路是通过CSS变量定义不同主题的样式属性,再结合Blazor的JavaScript互操作能力动态修改根节点的CSS变量值,同时可以将用户选择的主题状态持久化存储,避免页面刷新后主题重置。

实现原理概述
主题切换的本质是修改页面中生效的样式规则,Blazor作为前端框架,本身不直接操作DOM样式,因此需要借助CSS变量和JavaScript的配合:
- 首先在CSS中定义不同主题对应的变量集合,比如浅色主题和深色主题的背景色、文字色等
- 通过JavaScript方法修改<html>或<body>标签上的CSS变量值,实现样式的动态切换
- Blazor通过IJSRuntime接口调用JavaScript方法,完成主题切换的逻辑触发
- 使用localStorage存储用户选择过的主题,下次访问时自动加载对应主题
步骤一:定义CSS主题变量
在项目的wwwroot/css/app.css文件中定义根作用域的CSS变量,同时预设浅色和深色两套主题的变量值,默认先加载浅色主题:
:root {
/* 浅色主题默认值 */
--primary-bg-color: #ffffff;
--primary-text-color: #333333;
--secondary-bg-color: #f5f5f5;
--border-color: #e0e0e0;
}
/* 深色主题变量 */
[data-theme="dark"] {
--primary-bg-color: #1a1a1a;
--primary-text-color: #e0e0e0;
--secondary-bg-color: #2d2d2d;
--border-color: #444444;
}
body {
background-color: var(--primary-bg-color);
color: var(--primary-text-color);
transition: background-color 0.3s ease, color 0.3s ease;
}
.card {
background-color: var(--secondary-bg-color);
border: 1px solid var(--border-color);
padding: 16px;
border-radius: 8px;
margin: 8px 0;
}
步骤二:编写JavaScript切换方法
在wwwroot/js/app.js中编写操作主题切换的JavaScript方法,包括设置主题、获取当前主题、初始化主题三个核心方法:
// 设置主题,接收主题名称参数
function setTheme(themeName) {
// 给html标签设置data-theme属性,匹配CSS中的深色主题规则
document.documentElement.setAttribute('data-theme', themeName);
// 将主题存储到localStorage
localStorage.setItem('blazor-theme', themeName);
}
// 获取当前存储的主题
function getTheme() {
return localStorage.getItem('blazor-theme') || 'light';
}
// 初始化主题,页面加载时调用
function initTheme() {
const savedTheme = getTheme();
setTheme(savedTheme);
}
步骤三:在Blazor中调用JavaScript方法
在Blazor组件中注入IJSRuntime接口,通过它调用上面定义的JavaScript方法,同时实现主题切换的交互逻辑。
如果是Blazor WebAssembly项目,先在Program.cs中引入自定义的JavaScript文件:
// Program.cs
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");
// 引入自定义js文件
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
await builder.Build().RunAsync();
然后在_ViewImports.cshtml(Server项目)或index.html(WebAssembly项目)中引入js文件:
<script src="js/app.js"></script>
步骤四:实现主题切换组件
创建一个可复用的主题切换组件ThemeSwitcher.razor,包含主题切换的按钮和逻辑:
@inject IJSRuntime JSRuntime
@code {
private string currentTheme = "light";
protected override async Task OnInitializedAsync()
{
// 初始化时获取当前主题
currentTheme = await JSRuntime.InvokeAsync<string>("getTheme");
}
private async Task SwitchTheme()
{
// 切换主题,当前是浅色就切深色,反之切浅色
currentTheme = currentTheme == "light" ? "dark" : "light";
await JSRuntime.InvokeVoidAsync("setTheme", currentTheme);
}
}
<div class="card">
<p>当前主题:@(currentTheme == "light" ? "浅色主题" : "深色主题")</p>
<button @onclick="SwitchTheme" class="btn btn-primary">
切换到@(currentTheme == "light" ? "深色" : "浅色")主题
</button>
</div>
步骤五:初始化主题加载
为了让页面加载时自动应用用户上次选择的主题,需要在应用入口页面(比如App.razor或者MainLayout.razor)的OnInitialized生命周期中调用初始化方法:
@inject IJSRuntime JSRuntime
@code {
protected override async Task OnInitializedAsync()
{
await JSRuntime.InvokeVoidAsync("initTheme");
}
}
常见问题说明
主题切换没有生效
首先检查CSS变量的定义是否正确,确保深色主题的[data-theme="dark"]选择器优先级足够,同时确认JavaScript方法正确修改了html标签的data-theme属性。可以在浏览器开发者工具的Elements面板中查看html标签的属性变化。
页面刷新后主题重置
确认localStorage的读写逻辑是否正常,initTheme方法是否在应用初始化时正确调用。可以在浏览器开发者工具的Application面板的Local Storage中查看是否有blazor-theme这个存储项。
Blazor Server项目的差异
Blazor Server项目的JavaScript互操作逻辑和WebAssembly一致,只是JavaScript文件的引入位置在_Host.cshtml中,同时需要注意Server项目的预渲染可能会导致主题闪烁,可以在_Host.cshtml的head中添加内联的初始化脚本避免这个问题:
<script>
(function() {
const savedTheme = localStorage.getItem('blazor-theme') || 'light';
document.documentElement.setAttribute('data-theme', savedTheme);
})();
</script>
Blazor主题切换CSS变量JavaScript互操作Blazor_WebAssembly修改时间:2026-07-23 15:45:37