Blazor WebAssembly&MudBlazor模板集成
目录
MudBlazor组件库丰富且其组件名辨识度极高,UI设计上很不错。在纯Blazor WebAssembly Standalone模板上缺少了MudBlazor模板,因此集成时缺少参考文档。
新建项目
项目为Blazor WebAssembly Standalone模板。本文使用DotNet CLI快速搭建。
dotnet new blazorwasm -n AppDemo -f net9.0
dotnet new sln
dotnet sln add .\AppDemo\
集成MudBlazor包
只需一个包即可,样式文件和组件都在包中。
dotnet add package MudBlazor --version 8.14.0
服务注册
builder.Services.AddMudServices();
MudBlazor包方面完成了,接下来参照MudBlazor文档要求修改
删除原有所有css文件
默认Blazor WebAssembly Standalone模板wwwroot下为Bootstrap样式,可以全部移除,

修改index.html
替换Head
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>AppDemo</title>
<base href="/" />
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" rel="stylesheet" />
<link href="_content/MudBlazor/MudBlazor.min.css?v=1" rel="stylesheet" />
<link rel="icon" type="image/png" href="favicon.png" />
</head>
替换Script
<script src="_framework/blazor.webassembly.js"></script>
<script src="_content/MudBlazor/MudBlazor.min.js?v=1"></script>
默认index.html模板中有一段是动画交互效果。
<div id="app">
<svg class="loading-progress">
<circle r="40%" cx="50%" cy="50%" />
<circle r="40%" cx="50%" cy="50%" />
</svg>
<div class="loading-progress-text"></div>
</div>
MudBlazor模板没有这段替换内容。可自己实现一段,我实现了如下这段。
<div id="app">
<style>
#app {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100vh;
}
.loading-progress {
width: 100px;
height: 100px;
transform: rotate(-90deg);
}
.loading-progress circle {
fill: none;
stroke-width: 8;
stroke-linecap: round;
}
.loading-progress circle:first-child {
stroke: #e0e0e0;
}
.loading-progress circle:last-child {
stroke: #1976d2;
stroke-dasharray: 251.2;
stroke-dashoffset: 251.2;
animation: loading-progress 2s linear infinite;
}
@keyframes loading-progress {
0% {
stroke-dashoffset: 251.2;
}
50% {
stroke-dashoffset: 0;
}
100% {
stroke-dashoffset: -251.2;
}
}
.loading-progress-text {
margin-top: 20px;
font-family: 'Roboto', sans-serif;
font-size: 14px;
color: #666;
}
</style>
<svg class="loading-progress" viewBox="0 0 100 100">
<circle cx="50" cy="50" r="40" />
<circle cx="50" cy="50" r="40" />
</svg>
<div class="loading-progress-text">加载中...</div>
</div>
至于报错重新启动那段内容则挪动到MainLayout模板页中。最终的Index.html内容为
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>AppDemo</title>
<base href="/" />
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" rel="stylesheet" />
<link href="_content/MudBlazor/MudBlazor.min.css?v=1" rel="stylesheet" />
<link rel="icon" type="image/png" href="favicon.png" />
</head>
<body>
<div id="app">
<style>
#app {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100vh;
}
.loading-progress {
width: 100px;
height: 100px;
transform: rotate(-90deg);
}
.loading-progress circle {
fill: none;
stroke-width: 8;
stroke-linecap: round;
}
.loading-progress circle:first-child {
stroke: #e0e0e0;
}
.loading-progress circle:last-child {
stroke: #1976d2;
stroke-dasharray: 251.2;
stroke-dashoffset: 251.2;
animation: loading-progress 2s linear infinite;
}
@keyframes loading-progress {
0% {
stroke-dashoffset: 251.2;
}
50% {
stroke-dashoffset: 0;
}
100% {
stroke-dashoffset: -251.2;
}
}
.loading-progress-text {
margin-top: 20px;
font-family: 'Roboto', sans-serif;
font-size: 14px;
color: #666;
}
</style>
<svg class="loading-progress" viewBox="0 0 100 100">
<circle cx="50" cy="50" r="40" />
<circle cx="50" cy="50" r="40" />
</svg>
<div class="loading-progress-text">加载中...</div>
</div>
<script src="_framework/blazor.webassembly.js"></script>
<script src="_content/MudBlazor/MudBlazor.min.js?v=1"></script>
</body>
</html>
修改MainLayout
MudBlazor提供了完整的管理布局,直接替换即可。核心部分分别是顶部状态栏,左侧菜单和右侧内容块。
@inherits LayoutComponentBase
<MudThemeProvider />
<MudPopoverProvider />
<MudDialogProvider />
<MudSnackbarProvider />
<MudLayout>
<MudAppBar Elevation="1">
<MudIconButton Icon="@Icons.Material.Filled.Menu" Color="Color.Inherit" Edge="Edge.Start" OnClick="@((e) => DrawerToggle())" />
<MudText Typo="Typo.h5" Class="mt-1">Application</MudText>
<MudSpacer />
</MudAppBar>
<MudDrawer @bind-Open="_drawerOpen" ClipMode="DrawerClipMode.Always" Elevation="2">
<NavMenu />
</MudDrawer>
<MudMainContent Class="mt-16 pa-4">
@Body
</MudMainContent>
</MudLayout>
<div id="blazor-error-ui" data-nosnippet>
An unhandled error has occurred.
<a href="." class="reload">Reload</a>
<span class="dismiss">🗙</span>
</div>
@code {
private bool _drawerOpen = true;
void DrawerToggle()
{
_drawerOpen = !_drawerOpen;
}
}
在_Imports.razor中添加引用命名空间
@using MudBlazor
修改NavMenu
替换NavMenu内容以支持MudBlazor风格。
<MudNavMenu>
<MudNavLink Href="/" Match="NavLinkMatch.All" Icon="@Icons.Material.Filled.Home">Home</MudNavLink>
<MudNavLink Href="/counter" Match="NavLinkMatch.Prefix" Icon="@Icons.Material.Filled.Add">Counter</MudNavLink>
<MudNavLink Href="/weather" Match="NavLinkMatch.Prefix" Icon="@Icons.Material.Filled.Cloud">Weather</MudNavLink>
</MudNavMenu>
如此一来,基本的布局便是有了雏形。

修改Counter
参照MudBlazor的使用方式,替换Counter代码,熟悉使用。
https://mudblazor.com/getting-started/usage#quick-start
@page "/counter"
<PageTitle>Counter</PageTitle>
<MudText Typo="Typo.h6">MudBlazor is @Text</MudText>
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="ButtonOnClick">@ButtonText</MudButton>
@code {
public string Text { get; set; } = "????";
public string ButtonText { get; set; } = "Click Me";
public int ButtonClicked { get; set; }
void ButtonOnClick()
{
ButtonClicked += 1;
Text = $"Awesome x {ButtonClicked}";
ButtonText = "Click Me Again";
}
}
从其结构上看很清晰明了,特别是<Mud前缀一眼便能识别出这是个MudBlazor的组件。模板的引入便完成了,剩下便是集成页面工作。
参考文档
https://mudblazor.com/getting-started/installation#online-playground
2025-08-12,望技术有成后能回来看见自己的脚步。