Blazor 组件模型
创建 Razor 组件,了解组件生命周期,并使用参数和级联值。
Blazor 组件模型 是 CoddyKit 上的免费 C# Academy 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C# Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C# Academy 课程共包含 4 节课。
什么是 Blazor?
Blazor 让您可以使用 C# 而非 JavaScript 构建交互式 Web 用户界面。组件定义在 .razor 文件中,将 HTML 标记与 C# 逻辑结合起来。Blazor 可以在服务器上运行(Blazor Server),也可以通过 WebAssembly(Blazor WASM)在浏览器中运行。
您的第一个组件
Razor 组件是一个包含 HTML 标记和 C# @code 块的 .razor 文件。组件名称会成为 HTML 标签名称。
@* Greeting.razor *@
<h2>Hello, @Name!</h2>
<p>You have @Count messages.</p>
@code {
[Parameter] public string Name { get; set; } = "World";
private int Count = 5;
}组件生命周期
Blazor 组件具有一个包含可重写钩子的生命周期。最常用的钩子是 OnInitializedAsync(加载数据)和 OnParametersSetAsync(响应参数变化)。
@code {
private List<Product> Products = new();
protected override async Task OnInitializedAsync()
{
// Called once on first render
Products = await Http.GetFromJsonAsync<List<Product>>("/api/products")
?? new();
}
protected override async Task OnParametersSetAsync()
{
// Called whenever parameters change
await LoadDataAsync();
}
}参数:向组件传递数据
使用 [Parameter] 修饰属性,以便从父组件接收数据。参数会在渲染前设置,发生变化时可能触发重新渲染。
@* ProductCard.razor *@
<div class="card">
<h4>@Product.Name</h4>
<p>Price: @Product.Price.ToString("C")</p>
<button @onclick="AddToCart">Add to Cart</button>
</div>
@code {
[Parameter, EditorRequired]
public Product Product { get; set; } = default!;
[Parameter]
public EventCallback<Product> OnAddToCart { get; set; }
private async Task AddToCart() =>
await OnAddToCart.InvokeAsync(Product);
}级联参数
级联参数会向下流经组件树,无需显式地逐层传递——非常适合主题、用户信息或共享状态。
@* App.razor — wraps the whole app *@
<CascadingValue Value="CurrentUser">
<Router AppAssembly="@typeof(App).Assembly">
<Found Context="routeData">
<RouteView RouteData="routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
</Router>
</CascadingValue>
@* Anywhere in the tree: *@
@code {
[CascadingParameter]
public UserInfo CurrentUser { get; set; } = default!;
}渲染列表和条件内容
使用 Razor 指令 @if、@foreach 和 @for 渲染动态内容。请始终为列表项提供 @key,以便高效地进行差异比较。
@if (Products.Count == 0)
{
<p>No products found.</p>
}
else
{
<ul>
@foreach (var product in Products)
{
<li @key="product.Id">
<ProductCard Product="product" OnAddToCart="HandleAdd" />
</li>
}
</ul>
}RenderFragment 与 ChildContent
使用 RenderFragment 将标记作为参数传递——类似于 Vue 中的插槽或 React 中的子元素。约定使用的参数名称是 ChildContent。
@* Panel.razor *@
<div class="panel">
<div class="panel-header">@Title</div>
<div class="panel-body">@ChildContent</div>
</div>
@code {
[Parameter] public string Title { get; set; } = "";
[Parameter] public RenderFragment? ChildContent { get; set; }
}
@* Usage: *@
<Panel Title="Order Details">
<p>Order #42 — Shipped</p>
</Panel>使用 @ref 引用组件
使用 @ref 捕获对子组件的引用,以便从父组件调用其公共方法或读取其属性。
@* Parent.razor *@
<ConfirmDialog @ref="_dialog" OnConfirm="DeleteOrder" />
<button @onclick="() => _dialog!.Show()">Delete Order</button>
@code {
private ConfirmDialog? _dialog;
private async Task DeleteOrder()
{
await OrderService.DeleteAsync(CurrentOrderId);
// Refresh UI...
}
}StateHasChanged 与手动重新渲染
Blazor 会在事件处理程序执行后自动重新渲染。对于事件处理程序之外发生的异步状态变化(例如来自后台计时器的变化),请手动调用 StateHasChanged()。
@implements IDisposable
<p>Time: @CurrentTime</p>
@code {
private string CurrentTime = "";
private Timer? _timer;
protected override void OnInitialized()
{
_timer = new Timer(_ =>
{
CurrentTime = DateTime.Now.ToString("HH:mm:ss");
InvokeAsync(StateHasChanged); // thread-safe re-render
}, null, 0, 1000);
}
public void Dispose() => _timer?.Dispose();
}使用 ShouldRender 优化性能
重写 ShouldRender() 以跳过不必要的重新渲染。当组件输出不会变化时返回 false,从而减少差异比较开销。
@code {
private string _lastRenderedStatus = "";
[Parameter] public string Status { get; set; } = "";
protected override bool ShouldRender()
{
// Only re-render if Status actually changed
if (Status == _lastRenderedStatus) return false;
_lastRenderedStatus = Status;
return true;
}
}真实场景:产品列表组件
一个完整的产品列表组件:它会在初始化时加载数据、处理加载状态,并将事件传递给父组件。
@inject HttpClient Http
@if (_loading)
{
<p>Loading products...</p>
}
else
{
@foreach (var p in _products)
{
<ProductCard Product="p" OnAddToCart="AddToCart" />
}
}
@code {
private List<Product> _products = new();
private bool _loading = true;
[Parameter] public EventCallback<Product> OnCartUpdated { get; set; }
protected override async Task OnInitializedAsync()
{
_products = await Http.GetFromJsonAsync<List<Product>>("/api/products")
?? new();
_loading = false;
}
private async Task AddToCart(Product p) => await OnCartUpdated.InvokeAsync(p);
}快速检查
Blazor 组件初始化时,应在哪个生命周期方法中从 API 加载数据?
回顾:Blazor 组件模型
要点:
- .razor 文件将 HTML 标记与 @code 块中的 C# 混合在一起
- [Parameter] 接收来自父组件的数据;EventCallback 向上传递事件
- CascadingParameter 向下传递数据,无需逐层传递属性
- RenderFragment/ChildContent 创建可组合的基于插槽的组件
- 使用 OnInitializedAsync 加载初始数据;使用 StateHasChanged 手动重新渲染
- ShouldRender() 跳过不必要的差异比较,以提升性能
常见问题解答
「Blazor 组件模型」课时是免费的吗?
是的 — 「Blazor 组件模型」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C# Academy 课程的其余内容,请升级到 CoddyKit PRO。 C# Academy 课程共包含 4 节课。
「Blazor 组件模型」这节课中我会学到什么?
创建 Razor 组件,了解组件生命周期,并使用参数和级联值。 你通过在浏览器中直接运行的动手代码来练习 C# Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 C# Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 C# Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。
「Blazor 组件模型」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 C# Academy 课中编写并运行代码吗?
能。每节 C# Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- Blazor 组件模型
- 数据绑定与事件处理
- 组件通信与 DI
- Blazor 中的状态管理