6.2.1 Blazor 组件基础
Blazor 组件把 UI、参数、事件和渲染逻辑封装在 .razor 文件中。它适合 .NET 开发者用 C# 构建交互式前端。
学习目标
- 能创建一个可复用 Blazor 组件。
- 能使用
[Parameter]接收父组件数据。 - 能使用
EventCallback把用户操作传回父组件。 - 能区分展示组件和承载状态的页面组件。
应用场景
- 任务卡片、表单输入、分页器、筛选器等可复用 UI。
- 管理后台、内部系统、数据录入应用。
- 希望前后端都使用 C# 的团队项目。
核心概念
| 概念 | 说明 |
|---|---|
| 组件 | .razor 文件,封装 UI 和交互逻辑 |
| 参数 | 父组件传给子组件的数据 |
| 事件回调 | 子组件通知父组件发生了什么 |
| 状态 | 影响渲染结果的数据 |
案例:任务卡片组件
TodoCard.razor:
<article class="todo-card @(Todo.IsCompleted ? "todo-card--done" : null)">
<h3>@Todo.Title</h3>
@if (!string.IsNullOrWhiteSpace(Todo.Description))
{
<p>@Todo.Description</p>
}
<button disabled="@Todo.IsCompleted" @onclick="CompleteAsync">
@(Todo.IsCompleted ? "已完成" : "标记完成")
</button>
</article>
@code {
[Parameter, EditorRequired]
public required TodoItemDto Todo { get; set; }
[Parameter]
public EventCallback<int> OnComplete { get; set; }
private Task CompleteAsync() => OnComplete.InvokeAsync(Todo.Id);
}
TodoItemDto.cs:
public sealed record TodoItemDto(
int Id,
string Title,
string? Description,
bool IsCompleted);
示例:父组件使用子组件
@page "/todos"
<h1>任务列表</h1>
@foreach (var todo in todos)
{
<TodoCard Todo="todo" OnComplete="HandleCompleteAsync" />
}
@code {
private List<TodoItemDto> todos =
[
new(1, "学习 Minimal API", "完成第一个接口", false),
new(2, "学习 Blazor 组件", null, false),
];
private Task HandleCompleteAsync(int id)
{
var index = todos.FindIndex(todo => todo.Id == id);
if (index >= 0)
{
var current = todos[index];
todos[index] = current with {IsCompleted = true};
}
return Task.CompletedTask;
}
}
重点难点
- 子组件不要直接修改父组件的集合状态,应通过事件回调通知父组件。
[EditorRequired]是开发期提示,不替代运行时校验。- 组件过大时要拆分展示、表单和数据加载职责。
- 异步事件处理要返回
Task,不要使用async void。
常见误区
| 误区 | 推荐做法 |
|---|---|
| 所有 UI 都写在一个页面里 | 提取可复用组件并用参数传值 |
| 子组件直接调用全局状态 | 优先通过参数和事件形成清晰数据流 |
| 忽略加载和错误状态 | 为 API 调用设计 loading、empty、error 三种状态 |
练习
- 给
TodoCard增加删除按钮和OnDelete回调。 - 增加一个
Priority字段,并用 CSS 显示不同优先级。 - 把示例中的内存数据替换为调用后端 API。