mcpField
B
blazor

blazor

github.com/managedcode开发49639 次安装1 天前更新
代码仓库

关于 blazor

面向 Blazor 交互式 Web 界面开发的技能,涵盖渲染模式选择、组件设计、状态处理、预渲染、性能和 JavaScript 互操作,也涉及连接 AI 后端。

主要功能

  1. 01选择 Static、Server、WebAssembly 或 Auto 渲染模式
  2. 02设计可复用组件与状态管理
  3. 03处理预渲染和状态持久化
  4. 04使用 JavaScript 互操作
  5. 05优化列表渲染与性能

适用场景

  1. 01用 C# 构建交互式 Web 界面
  2. 02按 SEO、实时性或离线需求选择渲染模式
  3. 03避免预渲染与水合期间重复获取数据

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/managedcode/dotnet-skills --skill blazor

安装后在 Claude Code 中输入/blazor确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

manifest.json
references/
anti-patterns.md
patterns.md

详细介绍

Blazor

适用场景

  • 使用 C# 而非 JavaScript 构建交互式 Web UI
  • 在 Server、WebAssembly 或 Auto 渲染模式之间进行选择
  • 设计组件层次结构和状态管理
  • 处理预渲染和水合
  • 必要时与 JavaScript 集成
  • 将 Blazor UI 连接到 AI 后端,并使用 .NET 构建 AI Agent

文档

参考资料

渲染模式(.NET 8+)

模式运行位置适用场景
Static服务端(无交互性)SEO 页面、营销内容
InteractiveServer通过 SignalR 在服务端运行实时应用、轻量客户端
InteractiveWebAssembly通过 WASM 在浏览器中运行支持离线、客户端负载较重
InteractiveAuto先在服务端运行,然后在 WASM 中运行兼具两者优势
应用渲染模式
@* Per-component *@
@rendermode InteractiveServer

@* Or in App.razor for global *@
<Routes @rendermode="InteractiveAuto" />
InteractiveAuto 架构
First Request:
  Browser → Server (Interactive Server) → Fast response

Subsequent Requests:
  Browser → WASM (downloaded in background) → No server needed

工作流

  1. 根据需求选择渲染模式:

    • 需要 SEO?从 Static 或预渲染开始
    • 需要实时交互?使用 InteractiveServer
    • 需要离线支持?使用 InteractiveWebAssembly
    • 两者都需要?使用 InteractiveAuto
  2. 设计可复用组件:

    • 组件小巧、专注
    • 使用参数进行自定义
    • 使用事件进行通信
  3. 正确处理状态:

    • 组件状态保存在组件内
    • 使用服务(DI)共享状态
    • 使用 [PersistentState] 在预渲染期间持久化状态
  4. 在两种环境中验证(针对 Auto 模式)

当前上游说明

  • 将 dotnet/aspnetcore v10.0.11 视为维护版本。此版本修复了客户端持久化的电路状态过期后无法恢复的问题;升级时请重新运行重连、持久化状态过期、渲染模式以及 interactive-auto 客户端/服务端拆分测试。
  • 2026 年 8 月的 ASP.NET Core 概述仍将 Blazor 定位为组件 UI 方案。维护更新本身不会改变组件或渲染模式架构。

组件模式

基本组件
@* Counter.razor *@
<button @onclick="IncrementCount">
    Clicked @count times
</button>

@code {
    private int count = 0;

    [Parameter]
    public int InitialCount { get; set; } = 0;

    protected override void OnInitialized()
    {
        count = InitialCount;
    }

    private void IncrementCount() => count++;
}
参数和事件回调
@* Parent.razor *@
<ChildComponent Value="@value" ValueChanged="@OnValueChanged" />

@* ChildComponent.razor *@
@code {
    [Parameter] public string Value { get; set; } = "";
    [Parameter] public EventCallback<string> ValueChanged { get; set; }

    private async Task UpdateValue(string newValue)
    {
        await ValueChanged.InvokeAsync(newValue);
    }
}
状态持久化(.NET 8+)
@* Prevents double-fetch during prerender + hydration *@
@code {
    [PersistentState]
    public List<Product> Products { get; set; } = [];

    protected override async Task OnInitializedAsync()
    {
        // Only fetches once, persisted across prerender
        Products ??= await Http.GetFromJsonAsync<List<Product>>("api/products");
    }
}

Auto 模式的数据访问模式

// Shared interface
public interface IProductService
{
    Task<List<Product>> GetProductsAsync();
}

// Server implementation (direct DB access)
public class ServerProductService : IProductService
{
    private readonly AppDbContext _db;
    public async Task<List<Product>> GetProductsAsync()
        => await _db.Products.ToListAsync();
}

// Client implementation (HTTP call)
public class ClientProductService : IProductService
{
    private readonly HttpClient _http;
    public async Task<List<Product>> GetProductsAsync()
        => await _http.GetFromJsonAsync<List<Product>>("api/products");
}

// Registration
// Server: builder.Services.AddScoped<IProductService, ServerProductService>();
// Client: builder.Services.AddScoped<IProductService, ClientProductService>();

应避免的反模式

反模式不足之处更好的做法
组件过大难以维护,渲染速度慢拆分成更小的组件
在 WASM 中直接访问数据库浏览器中没有数据库使用 HTTP API
忽略 ShouldRender不必要的重新渲染按需重写
在 Server 中进行同步 JS 互操作阻塞 SignalR 电路异步使用 IJSRuntime
没有错误边界一个错误就会导致应用崩溃使用 <ErrorBoundary>
忘记预渲染状态导致 API 调用两次使用 [PersistentState]

性能最佳实践

  1. 虚拟化大型列表:

    <Virtualize Items="@products" Context="product">
        <ProductCard Product="@product" />
    </Virtualize>
    
  2. 使用 @key 进行列表差异比对:

    @foreach (var item in items)
    {
        <ItemComponent @key="item.Id" Item="@item" />
    }
    
  3. 对频繁触发的事件进行防抖处理:

    private Timer? _debounceTimer;
    
    private void OnInput(ChangeEventArgs e)
    {
        _debounceTimer?.Dispose();
        _debounceTimer = new Timer(_ => InvokeAsync(DoSearch), null, 300, Timeout.Infinite);
    }
    
  4. 延迟加载程序集(WASM):

    var assemblies = await LazyAssemblyLoader
        .LoadAssembliesAsync(["MyHeavyFeature.wasm"]);
    

JS 互操作

从 C# 调用 JavaScript
@inject IJSRuntime JS

await JS.InvokeVoidAsync("alert", "Hello from Blazor!");
var result = await JS.InvokeAsync<string>("prompt", "Enter name:");
从 JavaScript 调用 C#
[JSInvokable]
public static string GetMessage() => "Hello from C#!";
DotNet.invokeMethodAsync('MyAssembly', 'GetMessage')
    .then(result => console.log(result));

交付

  • 具有适当渲染模式的交互式 Blazor 组件
  • 高效的状态管理和数据流
  • 正确处理预渲染场景
  • 通过虚拟化实现高性能列表渲染

验证

  • 组件在所选模式下正确渲染
  • 状态在预渲染和水合过程中正确保留
  • 无不必要的重新渲染(使用浏览器工具检查)
  • JS 互操作在 Server 和 WASM 中均可正常工作
  • 错误边界能够捕获组件故障
  • Auto 模式在两种环境中均可正常工作

评论

支持 Markdown