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样式,可以全部移除,

204052678_a21b618f-9eeb-4eb4-beed-5d782fe55932

修改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>

如此一来,基本的布局便是有了雏形。 204053918_d3014715-c034-411c-acc3-62fc0a34fca1

修改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,望技术有成后能回来看见自己的脚步。