说明
此版本不是本文的最新版本。 有关当前版本,请参阅 .NET 9 版本的本文。
警告
此版本的 ASP.NET Core 不再受支持。 有关详细信息,请参阅 .NET 和 .NET Core 支持策略。 有关当前版本,请参阅 .NET 9 版本的本文。
重要
此信息与预发布产品相关,相应产品在商业发布之前可能会进行重大修改。 Microsoft 对此处提供的信息不提供任何明示或暗示的保证。
有关当前版本,请参阅 .NET 9 版本的本文。
本文介绍如何在 Razor 应用中创建和使用 Blazor 组件,包括有关 Razor 语法、组件命名、命名空间和组件参数的指导。
Razor 组件
Blazor 应用是使用 Razor 组件(非正式地称为 Blazor 组件或组件)构建的。 组件是用户界面 (UI) 的自包含部分,具有用于启用动态行为的处理逻辑。 组件可以嵌套、重用、在项目间共享,并可在 MVC 和 Razor Pages 应用中使用。
组件呈现为浏览器文档对象模型 (DOM) 的内存中表现形式,它被称为“呈现树”,用于以灵活高效的方式更新 UI。
尽管“Razor 组件”与其他 ASP.NET Core 内容呈现技术共享某种命名,但 Razor 组件必须与 ASP.NET Core 中的以下不同功能区分开来:
Razor 视图,它们是 MVC 应用的 Razor基于的标记页面。
视图组件,用于在 Razor Pages 和 MVC 应用中呈现内容块而不是整个响应。
重要
使用 Blazor Web App 时,大多数 Blazor 文档示例组件需要交互性才能运行并演示文章中涵盖的概念。
交互 使用户能够与呈现的组件进行互动。 这包括应用对 文档对象模型(DOM) 事件的响应,以及通过 Blazor的事件处理程序和绑定将状态更改关联到 C# 成员。 在 Blazor Web App中测试文章提供的示例组件时,请确保应用采用全局交互性或组件采用交互式呈现模式。 有关此主题的详细信息,请参阅 ASP.NET Core Blazor 呈现模式,即目录中本文后面的下一篇文章。
组件类
组件是使用 C# 和 HTML 标记的组合在 Razor 组件文件(文件扩展名为 .razor)中实现的。
ComponentBase 是 Razor 组件文件描述的组件的基类。
ComponentBase 实现组件的最低抽象,IComponent 接口。
ComponentBase 定义基本功能的组件属性和方法,例如,处理一组内置组件生命周期事件。
ComponentBase引用源中的 dotnet/aspnetcore:引用源包含有关内置生命周期事件的更多信息。 但是请记住,组件功能的内部实现随时可能会更改,但不会发出通知。
说明
指向 .NET 参考源的文档链接通常会加载存储库的默认分支,该分支表示针对下一个 .NET 版本的当前开发。 若要为特定版本选择标记,请使用“切换分支或标记”下拉列表。 有关详细信息,请参阅如何选择 ASP.NET Core 源代码的版本标记 (dotnet/AspNetCore.Docs #26205)。
开发人员通常从 Razor 组件文件 (Razor) 创建 .razor 组件,或将组件构建于 ComponentBase 之上,但组件也可以通过实现 IComponent 来生成。 实现 IComponent 的开发人员所构建的组件可以对呈现采用低级别控制,代价是需要使用事件和生命周期方法手动触发呈现,且这些事件和方法必须由开发人员创建和维护。
在 Blazor中,可以找到 Blazor 文档示例代码和示例应用所采用的其他约定。
Razor 语法
组件使用 Razor 语法。 组件广泛使用了两个 Razor 功能,即指令和指令特性。 这些是前缀为 @ 的保留关键字,出现在 Razor 标记中:
指令:更改组件标记的编译或运行方式。 例如,@page 指令会指定具有路由模板的可路由组件,用户在浏览器中通过特定 URL 发出请求即可直接访问。
按照约定,组件定义(.razor 文件)顶部的组件指令按一致顺序排列。 对于重复指令,指令按命名空间或类型按字母顺序放置,但具有特殊二级排序的 @using 指令除外。
Blazor 示例应用和文档采用以下顺序。
Blazor 项目模板提供的组件可能与以下顺序不同,并使用不同的格式。 例如,Blazor 框架 Identity 组件包括指令块 @using 和指令块 @inject 之间的空白行。 你可以在自己的应用中自由使用自定义排序方案和格式。
文档和示例应用 Razor 指令顺序:
@page
@rendermode(.NET 8 或更高版本)
@using
System 命名空间(字母顺序)
Microsoft 命名空间(字母顺序)
第三方 API 命名空间(字母顺序)
应用命名空间(字母顺序)
其他指令(字母顺序)
说明
呈现模式仅在 Blazor Web App 中应用,并包括用于与呈现的组件建立用户交互的模式。 有关详细信息,请参阅 ASP.NET Core Blazor 呈现模式。
指令之间没有出现空白行。 指令与 Razor 标记的第一行之间会出现一个空白行。
示例:
@page "/doctor-who-episodes/{season:int}"
@rendermode InteractiveWebAssembly
@using System.Globalization
@using System.Text.Json
@using Microsoft.AspNetCore.Localization
@using Mandrill
@using BlazorSample.Components.Layout
@attribute [Authorize]
@implements IAsyncDisposable
@inject IJSRuntime JS
@inject ILogger
...
指令特性:更改组件元素的编译方式或运行方式。
示例:
对于非显式@表达式 (Razor),可以使用 at 符号 (@bind="@episodeId") 为指令属性值添加前缀,但不建议使用,并且文档不会采用示例中的方法。
本文和 Blazor 文档集的其他文章中进一步说明了在组件中使用的指令和指令特性。 有关 Razor 语法的一般信息,请参阅 ASP.NET Core 的 Razor 语法参考。
组件名称、类名和命名空间
组件的名称必须以大写字符开头:
✔️支持:ProductDetail.razor
❌
不支持:productDetail.razor
整个 Blazor 文档中使用的常见 Blazor 命名约定包括:
文件路径和文件名使用 Pascal 大小写†,且在显示代码示例之前出现。 如果路径存在,则表示典型的文件夹位置。 例如,Components/Pages/ProductDetail.razor 表示 ProductDetail 组件具有文件名 ProductDetail.razor,并位于应用的 Pages 文件夹的 Components 文件夹中。
可路由组件的组件文件路径与其 ‡kebab 大小写形式的 URL 匹配,组件路由模板中各单词之间会显示连字符。 例如,一个具有路由模板 ProductDetail (/product-detail) 的 @page "/product-detail" 组件在浏览器中通过相对 URL /product-detail 被请求。
†Pascal 大小写(大写 camel 形式)是不带空格和标点符号的命名约定,其中每个单词的首字母大写(包括第一个单词)。
‡Kebab 大小写是一种命名约定,不使用空格和标点符号,它使用小写字母,且单词之间有短划线。
组件是普通 C# 类,可以放置在项目中的任何位置。 生成网页的组件通常位于 Components/Pages 文件夹中。 非页面组件通常放置在 Components 文件夹或添加到项目的自定义文件夹中。
通常,组件的命名空间是从应用的根命名空间和该组件在应用内的位置(文件夹)派生而来的。 如果应用的根命名空间是 BlazorSample,并且 Counter 组件位于 Components/Pages 文件夹中:
Counter 组件的命名空间为 BlazorSample.Components.Pages。
组件的完全限定类型名称为 BlazorSample.Components.Pages.Counter。
对于保存组件的自定义文件夹,将 @using 指令添加到父组件或应用的 _Imports.razor 文件。 下面的示例提供 AdminComponents 文件夹中的组件:
@using BlazorSample.AdminComponents
说明
@using 文件中的 _Imports.razor 指令仅适用于 Razor 文件 (.razor),而不适用于 C# 文件 (.cs)。
不支持使用别名的 using 语句。 在以下示例中,WeatherForecast 组件的公共 GridRendering 类作为应用其他位置的组件中的 WeatherForecast 提供:
@using WeatherForecast = Components.Pages.GridRendering.WeatherForecast
还可以使用其完全限定的名称来引用组件,这时不需要 @using 指令。 以下示例直接引用应用的 ProductDetail 文件夹中的 AdminComponents/Pages 组件:
使用 Razor 创建的组件的命名空间基于以下内容(按优先级顺序):
@namespace 文件标记中的 Razor 指令(例如 @namespace BlazorSample.CustomNamespace)。
项目文件中项目的 RootNamespace(例如 
项目命名空间和从项目根目录到组件的路径。 例如,框架将具有项目命名空间 {PROJECT NAMESPACE}/Components/Pages/Home.razor 的 BlazorSample 解析到 BlazorSample.Components.Pages 组件的命名空间 Home。
{PROJECT NAMESPACE} 为项目命名空间。 组件遵循 C# 名称绑定规则。 对于本示例中的 Home 组件,范围内的组件是所有组件:
在同一文件夹 Components/Pages 中。
未显式指定其他命名空间的项目根中的组件。
不支持以下项目:
global:: 限定。
部分限定的名称。 例如,无法将 @using BlazorSample.Components 添加到组件中,然后使用 NavMenu 在应用的 Components/Layout 文件夹中引用 Components/Layout/NavMenu.razor 组件 (
组件的名称必须以大写字符开头:
✔️支持:ProductDetail.razor
❌
不支持:productDetail.razor
整个 Blazor 文档中使用的常见 Blazor 命名约定包括:
文件路径和文件名使用 Pascal 大小写†,且在显示代码示例之前出现。 如果路径存在,则表示典型的文件夹位置。 例如,Pages/ProductDetail.razor 指示 ProductDetail 组件具有文件名 ProductDetail.razor,并位于应用的 Pages 文件夹中。
可路由组件的组件文件路径与其 ‡kebab 大小写形式的 URL 匹配,组件路由模板中各单词之间会显示连字符。 例如,一个具有路由模板 ProductDetail (/product-detail) 的 @page "/product-detail" 组件在浏览器中通过相对 URL /product-detail 被请求。
†Pascal 大小写(大写 camel 形式)是不带空格和标点符号的命名约定,其中每个单词的首字母大写(包括第一个单词)。
‡Kebab 大小写是一种命名约定,不使用空格和标点符号,它使用小写字母,且单词之间有短划线。
组件是普通 C# 类,可以放置在项目中的任何位置。 生成网页的组件通常位于 Pages 文件夹中。 非页面组件通常放置在 Shared 文件夹或添加到项目的自定义文件夹中。
通常,组件的命名空间是从应用的根命名空间和该组件在应用内的位置(文件夹)派生而来的。 如果应用的根命名空间是 BlazorSample,并且 Counter 组件位于 Pages 文件夹中:
Counter 组件的命名空间为 BlazorSample.Pages。
组件的完全限定类型名称为 BlazorSample.Pages.Counter。
对于保存组件的自定义文件夹,将 @using 指令添加到父组件或应用的 _Imports.razor 文件。 下面的示例提供 AdminComponents 文件夹中的组件:
@using BlazorSample.AdminComponents
说明
@using 文件中的 _Imports.razor 指令仅适用于 Razor 文件 (.razor),而不适用于 C# 文件 (.cs)。
不支持使用别名的 using 语句。 在以下示例中,WeatherForecast 组件的公共 GridRendering 类作为应用其他位置的组件中的 WeatherForecast 提供:
@using WeatherForecast = Pages.GridRendering.WeatherForecast
还可以使用其完全限定的名称来引用组件,这时不需要 @using 指令。 以下示例直接引用应用的 ProductDetail 文件夹中的 Components 组件:
使用 Razor 创建的组件的命名空间基于以下内容(按优先级顺序):
@namespace 文件标记中的 Razor 指令(例如 @namespace BlazorSample.CustomNamespace)。
项目文件中项目的 RootNamespace(例如 
项目命名空间和从项目根目录到组件的路径。 例如,框架将具有项目命名空间 {PROJECT NAMESPACE}/Pages/Index.razor 的 BlazorSample 解析到 BlazorSample.Pages 组件的命名空间 Index。
{PROJECT NAMESPACE} 为项目命名空间。 组件遵循 C# 名称绑定规则。 对于本示例中的 Index 组件,范围内的组件是所有组件:
在同一文件夹 Pages 中。
未显式指定其他命名空间的项目根中的组件。
不支持以下项目:
global:: 限定。
部分限定的名称。 例如,无法将 @using BlazorSample 添加到组件中,然后使用 NavMenu 在应用的 Shared 文件夹中引用 Shared/NavMenu.razor 组件 (
分部类支持
组件以 C# 分部类的形式生成,使用以下任一方法进行创作:
单个文件包含在一个或多个 @code 块、HTML 标记和 Razor 标记中定义的 C# 代码。
Blazor 项目模板使用此单文件方法来定义其组件。
HTML 和 Razor 标记位于 Razor 文件 (.razor) 中。 C# 代码位于定义为分部类的后置代码文件 (.cs) 中。
说明
定义特定于组件的样式的组件样式表是单独的文件 (.css)。
Blazor CSS 隔离稍后在 ASP.NET Core Blazor CSS 隔离 中进行介绍。
下面的示例显示了从 Counter 项目模板生成的应用中具有 @code 块的默认 Blazor 组件。 标记和 C# 代码位于同一个文件中。 这是在创作组件时采用的最常见方法。
Counter.razor:
@page "/counter"
Counter
Current count: @currentCount
@code {
private int currentCount = 0;
private void IncrementCount() => currentCount++;
}
@page "/counter"
Counter
Current count: @currentCount
@code {
private int currentCount = 0;
private void IncrementCount() => currentCount++;
}
@page "/counter"
Counter
Current count: @currentCount
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}
@page "/counter"
Counter
Current count: @currentCount
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}
@page "/counter"
Counter
Current count: @currentCount
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}
@page "/counter"
Counter
Current count: @currentCount
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}
以下 Counter 组件使用带有分部类的代码隐藏文件从 C# 代码中拆分呈现 HTML 和 Razor 标记。 一些组织和开发人员倾向于从 C# 代码拆分标记,借此组织其组件代码来适应他们偏好的工作方式。 例如,组织的 UI 专家可以独自处理呈现层,而不必依赖处理组件的 C# 逻辑的另一位开发人员。 使用自动生成的代码或源生成器时,此方法也很有用。 有关详细信息,请参阅分部类和方法(C# 编程指南)。
CounterPartialClass.razor:
@page "/counter-partial-class"
Counter
Current count: @currentCount
@page "/counter-partial-class"
Counter
Current count: @currentCount
@page "/counter-partial-class"
Counter
Current count: @currentCount
@page "/counter-partial-class"
Counter
Current count: @currentCount
@page "/counter-partial-class"
Counter
Current count: @currentCount
@page "/counter-partial-class"
Counter
Current count: @currentCount
CounterPartialClass.razor.cs:
namespace BlazorSample.Components.Pages;
public partial class CounterPartialClass
{
private int currentCount = 0;
private void IncrementCount() => currentCount++;
}
namespace BlazorSample.Components.Pages;
public partial class CounterPartialClass
{
private int currentCount = 0;
private void IncrementCount() => currentCount++;
}
namespace BlazorSample.Pages;
public partial class CounterPartialClass
{
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}
namespace BlazorSample.Pages
{
public partial class CounterPartialClass
{
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}
}
@using 文件中的 _Imports.razor 指令仅适用于 Razor 文件 (.razor),而不适用于 C# 文件 (.cs)。 根据需要将命名空间添加到分部类文件中。
组件使用的典型命名空间:
using System.Net.Http;
using System.Net.Http.Json;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Components.Routing;
using Microsoft.AspNetCore.Components.Sections
using Microsoft.AspNetCore.Components.Web;
using static Microsoft.AspNetCore.Components.Web.RenderMode;
using Microsoft.AspNetCore.Components.Web.Virtualization;
using Microsoft.JSInterop;
典型命名空间还包含应用的命名空间以及与应用的 Components 文件夹对应的命名空间:
using BlazorSample;
using BlazorSample.Components;
还可以包含其他文件夹,例如 Layout 文件夹:
using BlazorSample.Components.Layout;
using System.Net.Http;
using System.Net.Http.Json;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Components.Routing;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.Web.Virtualization;
using Microsoft.JSInterop;
典型命名空间还包含应用的命名空间以及与应用的 Shared 文件夹对应的命名空间:
using BlazorSample;
using BlazorSample.Shared;
using System.Net.Http;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Components.Routing;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.JSInterop;
典型命名空间还包含应用的命名空间以及与应用的 Shared 文件夹对应的命名空间:
using BlazorSample;
using BlazorSample.Shared;
指定基类
@inherits 指令用于指定组件的基类。 与使用分部类不同,它仅从 C# 逻辑拆分标记,使用基类可以继承 C# 代码,以便在共用基类的属性和方法的一组组件之间使用。 使用基类可减少应用中的代码冗余,在将基代码从类库提供给多个应用时非常有用。 有关详细信息,请参阅 C# 和 .NET 中的继承。
在下面的示例中,BlazorRocksBase1 基类派生自 ComponentBase。
BlazorRocks1.razor:
@page "/blazor-rocks-1"
@inherits BlazorRocksBase1
Blazor Rocks! Example 1
@BlazorRocksText
@page "/blazor-rocks-1"
@inherits BlazorRocksBase1
Blazor Rocks! Example 1
@BlazorRocksText
@page "/blazor-rocks-1"
@inherits BlazorRocksBase1
Blazor Rocks! Example 1
@BlazorRocksText
@page "/blazor-rocks-1"
@inherits BlazorRocksBase1
Blazor Rocks! Example 1
@BlazorRocksText
@page "/blazor-rocks-1"
@inherits BlazorRocksBase1
Blazor Rocks! Example 1
@BlazorRocksText
@page "/blazor-rocks-1"
@inherits BlazorRocksBase1
Blazor Rocks! Example 1
@BlazorRocksText
BlazorRocksBase1.cs:
using Microsoft.AspNetCore.Components;
namespace BlazorSample;
public class BlazorRocksBase1 : ComponentBase
{
public string BlazorRocksText { get; set; } = "Blazor rocks the browser!";
}
using Microsoft.AspNetCore.Components;
namespace BlazorSample;
public class BlazorRocksBase1 : ComponentBase
{
public string BlazorRocksText { get; set; } = "Blazor rocks the browser!";
}
using Microsoft.AspNetCore.Components;
namespace BlazorSample;
public class BlazorRocksBase1 : ComponentBase
{
public string BlazorRocksText { get; set; } =
"Blazor rocks the browser!";
}
using Microsoft.AspNetCore.Components;
namespace BlazorSample;
public class BlazorRocksBase1 : ComponentBase
{
public string BlazorRocksText { get; set; } =
"Blazor rocks the browser!";
}
using Microsoft.AspNetCore.Components;
namespace BlazorSample;
public class BlazorRocksBase1 : ComponentBase
{
public string BlazorRocksText { get; set; } =
"Blazor rocks the browser!";
}
using Microsoft.AspNetCore.Components;
namespace BlazorSample;
public class BlazorRocksBase1 : ComponentBase
{
public string BlazorRocksText { get; set; } =
"Blazor rocks the browser!";
}
路由
可以通过使用 Blazor 指令为应用中的每个可访问组件提供路由模板来实现 @page 中的路由。 编译具有 Razor 指令的 @page 文件时,将为生成的类提供指定路由模板的 RouteAttribute。 在运行时,路由器将使用 RouteAttribute 搜索组件类,并呈现具有与请求的 URL 匹配的路由模板的任何组件。
以下 HelloWorld 组件使用 /hello-world 的路由模板,可以通过相对 URL /hello-world 访问其呈现的网页。
HelloWorld.razor:
@page "/hello-world"
Hello World!
@page "/hello-world"
Hello World!
@page "/hello-world"
Hello World!
@page "/hello-world"
Hello World!
@page "/hello-world"
Hello World!
@page "/hello-world"
Hello World!
前面的组件在浏览器中通过 /hello-world 进行加载,无论是否将组件添加到应用的 UI 导航。 可选情况下,可以将组件添加到 NavMenu 组件中,以便在应用的基于 UI 的导航中显示指向该组件的链接。
对于前面的 HelloWorld 组件,可以将 NavLink 组件添加到 NavMenu 组件。 有关详细信息(包括对 NavLink 和 NavMenu 组件的描述),请参阅 ASP.NET Core Blazor 路由和导航。
标记
组件的 UI 使用由 Razor 标记、C# 和 HTML 组成的 进行定义。 在编译应用时,HTML 标记和 C# 呈现逻辑转换为组件类。 生成的类的名称与文件名匹配。
组件类的成员在一个或多个 @code 块中定义。 在 @code 块中,组件状态使用 C# 进行指定和处理:
属性和字段初始化表达式。
由父组件和路由参数传递的参数值。
用于用户事件处理、生命周期事件和自定义组件逻辑的方法。
组件成员使用以 @ 符号开头的 C# 表达式用于呈现逻辑。 例如,通过为字段名称添加 @ 前缀来呈现 C# 字段。 下面 Markup 组件计算并呈现:
headingFontStyle,表示标题元素的 CSS 属性值 font-style。
headingText,表示标题元素的内容。
Markup.razor:
@page "/markup"
Markup Example
@headingText
@code {
private string headingFontStyle = "italic";
private string headingText = "Put on your new Blazor!";
}
@page "/markup"
Markup Example
@headingText
@code {
private string headingFontStyle = "italic";
private string headingText = "Put on your new Blazor!";
}
@page "/markup"
@headingText
@code {
private string headingFontStyle = "italic";
private string headingText = "Put on your new Blazor!";
}
@page "/markup"
@headingText
@code {
private string headingFontStyle = "italic";
private string headingText = "Put on your new Blazor!";
}
@page "/markup"
@headingText
@code {
private string headingFontStyle = "italic";
private string headingText = "Put on your new Blazor!";
}
@page "/markup"
@headingText
@code {
private string headingFontStyle = "italic";
private string headingText = "Put on your new Blazor!";
}
说明
Blazor 文档中的示例为私有成员指定了 private 的访问修饰符。 私有成员的范围限定为组件的类。 但是,C# 会在没有访问修饰符存在时采用 private 访问修饰符,因此在自己的代码中将成员显式标记为“private”是可选的。 有关访问修饰符的详细信息,请参阅访问修饰符(C# 编程指南)。
Blazor 框架在内部将组件作为呈现树进行处理,该树是组件的文档对象模型 (DOM) 和级联样式表对象模型 (CSSOM) 的组合。 最初呈现组件后,会重新生成组件的呈现树以响应事件。
Blazor 会将新呈现树与以前的呈现树进行比较,并将所有修改应用于浏览器的 DOM 以进行显示。 有关详细信息,请参阅 ASP.NET Core Razor 组件呈现。
C# 控件结构、指令和指令属性的 Razor 语法需要小写(示例:@if、@code、@bind)。 属性名称需要大写(示例:@Body 的 LayoutComponentBase.Body)。
异步方法 (async) 不支持返回 void
Blazor 框架不跟踪返回 void 的异步方法 (async)。 因此,如果未捕获异常并且返回void,整个过程将失败。 异步方法始终应返回一个 Task/ValueTask。
嵌套组件
通过使用 HTML 语法声明组件,组件可以包含其他组件。 使用组件的标记类似于 HTML 标记,其中标记的名称是组件类型。
请考虑以下 Heading 组件,其他组件可以使用该组件显示标题。
Heading.razor:
Heading Example
@code {
private string headingFontStyle = "italic";
}
Heading Example
@code {
private string headingFontStyle = "italic";
}
Heading Example
@code {
private string headingFontStyle = "italic";
}
Heading Example
@code {
private string headingFontStyle = "italic";
}
Heading Example
@code {
private string headingFontStyle = "italic";
}
Heading Example
@code {
private string headingFontStyle = "italic";
}
HeadingExample 组件中的以下标记会在 Heading 标记出现的位置呈现前面的 
HeadingExample.razor:
@page "/heading-example"
Heading Example
@page "/heading-example"
Heading Example
@page "/heading-example"
@page "/heading-example"
@page "/heading-example"
@page "/heading-example"
如果某个组件包含一个 HTML 元素,该元素的大写首字母与相同命名空间中的组件名称不匹配,则会发出警告,指示该元素名称异常。 为组件的命名空间添加 @using 指令使组件可用,这可解决此警告。 有关详细信息,请参阅组件名称、类名和命名空间部分。
此部分中显示的 Heading 组件示例没有 @page 指令,因此用户无法在浏览器中通过直接请求直接访问 Heading 组件。 但是,具有 @page 指令的任何组件都可以嵌套在另一个组件中。 如果通过在 Heading 文件顶部包含 @page "/heading" 可直接访问 Razor组件,则会在 /heading 和 /heading-example 处为浏览器请求呈现该组件。
组件参数
组件参数将数据传递给组件,使用组件类中包含 的公共 [Parameter]进行定义。
在以下 ParameterChild 组件中,组件参数包括:
内置引用类型。
System.String 在 Title 中传递一个标题。
System.Int32 将计数传递到 Count。
用户定义的引用类型(PanelBody)用于在 Body中传递 Bootstrap 卡片内容。
PanelBody.cs:
namespace BlazorSample;
public class PanelBody
{
public string? Text { get; set; }
public string? Style { get; set; }
}
namespace BlazorSample;
public class PanelBody
{
public string? Text { get; set; }
public string? Style { get; set; }
}
public class PanelBody
{
public string? Text { get; set; }
public string? Style { get; set; }
}
public class PanelBody
{
public string? Text { get; set; }
public string? Style { get; set; }
}
public class PanelBody
{
public string Text { get; set; }
public string Style { get; set; }
}
public class PanelBody
{
public string Text { get; set; }
public string Style { get; set; }
}
ParameterChild.razor:
@Body.Text
@if (Count is not null)
{
The count is @Count.
}
@code {
[Parameter]
public string Title { get; set; } = "Set By Child";
[Parameter]
public PanelBody Body { get; set; } =
new()
{
Text = "Card content set by child.",
Style = "normal"
};
[Parameter]
public int? Count { get; set; }
}
@Body.Text
@if (Count is not null)
{
The count is @Count.
}
@code {
[Parameter]
public string Title { get; set; } = "Set By Child";
[Parameter]
public PanelBody Body { get; set; } =
new()
{
Text = "Card content set by child.",
Style = "normal"
};
[Parameter]
public int? Count { get; set; }
}
@Body.Text
@if (Count is not null)
{
The count is @Count.
}
@code {
[Parameter]
public string Title { get; set; } = "Set By Child";
[Parameter]
public PanelBody Body { get; set; } =
new()
{
Text = "Set by child.",
Style = "normal"
};
[Parameter]
public int? Count { get; set; }
}
@Body.Text
@if (Count is not null)
{
The count is @Count.
}
@code {
[Parameter]
public string Title { get; set; } = "Set By Child";
[Parameter]
public PanelBody Body { get; set; } =
new()
{
Text = "Set by child.",
Style = "normal"
};
[Parameter]
public int? Count { get; set; }
}
@Body.Text
@if (Count is not null)
{
The count is @Count.
}
@code {
[Parameter]
public string Title { get; set; } = "Set By Child";
[Parameter]
public PanelBody Body { get; set; } =
new()
{
Text = "Set by child.",
Style = "normal"
};
[Parameter]
public int? Count { get; set; }
}
@Body.Text
@if (Count is not null)
{
The count is @Count.
}
@code {
[Parameter]
public string Title { get; set; } = "Set By Child";
[Parameter]
public PanelBody Body { get; set; } =
new PanelBody()
{
Text = "Set by child.",
Style = "normal"
};
[Parameter]
public int? Count { get; set; }
}
警告
支持为组件参数提供初始值,但不会创建在首次呈现后向自身参数写入的组件。 有关详细信息,请参阅在 ASP.NET Core 中避免覆盖参数Blazor。
ParameterChild 组件的参数可以通过用于呈现 ParameterChild 组件实例的 HTML 标签中的参数进行设置。 以下父组件呈现两个 ParameterChild 组件:
第一个 ParameterChild 组件在渲染时不带参数。
第二个 ParameterChild 组件从父组件接收 Title 和 Body 的值,该组件使用 显式 C# 表达式 设置 PanelBody属性的值。
Parameter1.razor:
@page "/parameter-1"
Parameter Example 1
Child component (without attribute values)
Child component (with attribute values)
Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" /> Parameter1.razor: @page "/parameter-1"Parameter Example 1
Child component (without attribute values)
Child component (with attribute values)
Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" /> ParameterParent.razor: @page "/parameter-parent"Child component (without attribute values)
Child component (with attribute values)
Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" /> ParameterParent.razor: @page "/parameter-parent"Child component (without attribute values)
Child component (with attribute values)
Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" /> ParameterParent.razor: @page "/parameter-parent"Child component (without attribute values)
Child component (with attribute values)
Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" /> ParameterParent.razor: @page "/parameter-parent"Child component (without attribute values)
Child component (with attribute values)
Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" /> 父组件中呈现的以下 HTML 标记在父组件不提供组件参数值时显示 ParameterChild 组件默认值。 当父组件提供组件参数值时,它们将替换 ParameterChild 组件的默认值。 说明 为了清楚起见,大多数呈现的 CSS 样式类和某些元素不会显示在以下呈现的 HTML 标记中。 以下示例演示的主要概念是,父组件使用其组件参数将值分配给子组件。Child component (without attribute values)
Card content set by child.
Child component (with attribute values)
Set by parent.
将方法的 C# 字段、属性或结果作为 HTML 特性值分配给组件参数。 特性的值通常可以是与参数类型匹配的任何 C# 表达式。 特性的值可以选择性地以Razor 保留 @ 符号开头,但这不是必需的。
如果组件参数的类型为字符串,则会改为将特性值视为 C# 字符串字面量。 如果要改为指定 C# 表达式,请使用 @ 前缀。
以下父组件显示上述 ParameterChild 组件的四个实例,并将其 Title 参数值设置为:
title 字段的值。
GetTitle C# 方法的结果。
带有ToLongDateString 的长格式当前本地日期,使用隐式 C# 表达式。
panelData 对象的 Title 属性。
第五个 ParameterChild 组件实例还设置 Count 参数。 请注意,string类型化参数需要一个 @ 前缀,以确保表达式不被视为字符串文本。 但是,Count 是可为 null 的整数(System.Int32),因此 Count 可以接收不带 count 前缀的 @ 值。 可以建立一个替代代码约定,要求组织中的开发人员始终以 @为前缀。 无论哪种方式,我们只是建议您采用一致的方法来在 Razor 标记中传递组件参数。
在大多数情况下,根据 HTML5 规范,参数属性值的引号是可选的。 例如,支持 Value=this,而不是 Value="this"。 但是,我们建议使用引号,因为它更易于记住,并且在基于 Web 的技术中被广泛采用。
在整个文档中,代码示例:
始终使用引号。 示例:Value="this"。
除非必要,否则不要将 @ 前缀与非文本一起使用。 示例:Count="count",其中 count 是数字类型的变量。
Count="@count" 是一种有效的风格方法,但文档和示例不采用约定。
对于 @ 表达式之外的文本始终避免使用 Razor。 示例:IsFixed="true"。 这包括关键字(例如 this)和 null,但你可以根据需要选择使用它们。 例如,IsFixed="@true" 不常见,但受支持。
Parameter2.razor:
@page "/parameter-2"
Parameter Example 2
@code {
private string title = "From Parent field";
private PanelData panelData = new();
private int count = 12345;
private string GetTitle() => "From Parent method";
private class PanelData
{
public string Title { get; set; } = "From Parent object";
}
}
Parameter2.razor:
@page "/parameter-2"
Parameter Example 2
@code {
private string title = "From Parent field";
private PanelData panelData = new();
private int count = 12345;
private string GetTitle() => "From Parent method";
private class PanelData
{
public string Title { get; set; } = "From Parent object";
}
}
ParameterParent2.razor:
@page "/parameter-parent-2"
@code {
private string title = "From Parent field";
private PanelData panelData = new();
private int count = 12345;
private string GetTitle()
{
return "From Parent method";
}
private class PanelData
{
public string Title { get; set; } = "From Parent object";
}
}
ParameterParent2.razor:
@page "/parameter-parent-2"
@code {
private string title = "From Parent field";
private PanelData panelData = new();
private int count = 12345;
private string GetTitle()
{
return "From Parent method";
}
private class PanelData
{
public string Title { get; set; } = "From Parent object";
}
}
ParameterParent2.razor:
@page "/parameter-parent-2"
@code {
private string title = "From Parent field";
private PanelData panelData = new PanelData();
private int count = 12345;
private string GetTitle()
{
return "From Parent method";
}
private class PanelData
{
public string Title { get; set; } = "From Parent object";
}
}
说明
将 C# 成员分配给组件参数时,不要使用 @ 为参数的 HTML 特性添加前缀。
正确(Title 是字符串参数, Count 是数字类型的参数):
不正确:
与 Razor 页面 (.cshtml) 不同,在呈现组件时,Blazor 不能在 Razor 表达式中执行异步工作。 这是因为 Blazor 是为呈现交互式 UI 而设计的。 在交互式 UI 中,屏幕必须始终显示某些内容,因此阻止呈现流是没有意义的。 相反,异步工作是在一个异步生命周期事件期间执行的。 在每个异步生命周期事件之后,组件可能会再次渲染。 不Razor支持以下 语法:
生成应用时,前面示例中的代码会生成编译器错误:
“await”运算符只能用于异步方法中。 请考虑用“async”修饰符标记此方法,并将其返回类型更改为“Task”。
若要在前面的示例中异步获取 Title 参数的值,组件可以使用 OnInitializedAsync 生命周期事件,如以下示例所示:
@code {
private string? title;
protected override async Task OnInitializedAsync()
{
title = await ...;
}
}
有关详细信息,请参阅 ASP.NET Core Razor 组件生命周期。
不支持使用显式 Razor 表达式连接文本和表达式结果以赋值给参数。 下面的示例尝试将文本“Set by ”与对象属性值连接在一起。 尽管 Razor 页面 (.cshtml) 支持此语法,但对在组件中赋值给子级的 Title 参数无效。 不Razor支持以下 语法:
生成应用时,前面示例中的代码会生成编译器错误:
组件属性不支持复杂内容(混合 C# 和标记)。
若要支持组合值赋值,请使用方法、字段或属性。 下面的示例在 C# 方法 Set by 中将“GetTitle”与对象属性值连接在一起:
Parameter3.razor:
@page "/parameter-3"
Parameter Example 3
@code {
private PanelData panelData = new();
private string GetTitle() => $"Set by {panelData.Title}";
private class PanelData
{
public string Title { get; set; } = "Parent";
}
}
Parameter3.razor:
@page "/parameter-3"
Parameter Example 3
@code {
private PanelData panelData = new();
private string GetTitle() => $"Set by {panelData.Title}";
private class PanelData
{
public string Title { get; set; } = "Parent";
}
}
ParameterParent3.razor:
@page "/parameter-parent-3"
@code {
private PanelData panelData = new();
private string GetTitle() => $"Set by {panelData.Title}";
private class PanelData
{
public string Title { get; set; } = "Parent";
}
}
ParameterParent3.razor:
@page "/parameter-parent-3"
@code {
private PanelData panelData = new();
private string GetTitle() => $"Set by {panelData.Title}";
private class PanelData
{
public string Title { get; set; } = "Parent";
}
}
ParameterParent3.razor:
@page "/parameter-parent-3"
@code {
private PanelData panelData = new();
private string GetTitle() => $"Set by {panelData.Title}";
private class PanelData
{
public string Title { get; set; } = "Parent";
}
}
ParameterParent3.razor:
@page "/parameter-parent-3"
@code {
private PanelData panelData = new PanelData();
private string GetTitle() => $"Set by {panelData.Title}";
private class PanelData
{
public string Title { get; set; } = "Parent";
}
}
有关详细信息,请参阅 ASP.NET Core 的 Razor 语法参考。
警告
支持为组件参数提供初始值,但不会创建在首次呈现后向自身参数写入的组件。 有关详细信息,请参阅在 ASP.NET Core 中避免覆盖参数Blazor。
组件参数应声明为 自动实现的属性(自动属性),这意味着它们不应在其 get 或 set 访问器中包含自定义逻辑。 例如,以下 StartData 属性是自动属性:
[Parameter]
public DateTime StartData { get; set; }
不要在 get 或 set 访问器中放置自定义逻辑,因为组件参数专门用作父组件向子组件传送信息的通道。 如果子组件属性的 set 访问器包含导致父组件重新呈现的逻辑,则会导致一个无限的呈现循环。 其他副作用包括意外出现的多次渲染以及参数值的重写。
若要转换已接收的参数值,请执行以下操作:
将参数属性保留为自动属性,以表示所提供的原始数据。
创建另一个属性或方法,用于基于参数属性提供转换后的数据。
替代 OnParametersSetAsync 以在每次收到新数据时转换接收到的参数。
支持将初始值写入组件参数,因为初始值赋值不会干扰 Blazor 的自动组件呈现。 在组件中,使用 DateTime 将当前本地 DateTime.Now 赋予 StartData 是有效语法:
[Parameter]
public DateTime StartData { get; set; } = DateTime.Now;
进行 DateTime.Now 的初始赋值之后,请勿在开发人员代码中向 StartData 赋值。 有关详细信息,请参阅在 ASP.NET Core 中避免覆盖参数Blazor。
应用 [EditorRequired] 特性以指定所需的组件参数。 如果未提供参数值,编辑器或生成工具可能会向用户显示警告。 此特性仅在也用 [Parameter] 特性标记的属性上有效。 在设计时和生成应用时需强制使用 EditorRequiredAttribute。 在运行时则不强制使用该特性,因为它无法保证非 null 的参数值。
[Parameter]
[EditorRequired]
public string? Title { get; set; }
还支持单行特性列表:
[Parameter, EditorRequired]
public string? Title { get; set; }
不要对组件参数属性使用 required 修饰符或 init 访问器。 组件通常使用反射实例化和分配参数值,从而绕过了 init 和 required 本应做出的保证。 请改为使用 [EditorRequired] 特性以指定所需的组件参数。
不要对组件参数属性使用 init 访问器,因为设置具有 ParameterView.SetParameterProperties 的组件参数值会使用反射,这会绕过仅初始化的资源库限制。 应用 [EditorRequired] 特性以指定所需的组件参数。
不要对组件参数属性使用 init 访问器,因为设置具有 ParameterView.SetParameterProperties 的组件参数值会使用反射,这会绕过仅初始化的资源库限制。
组件参数和 Tuples 类型支持 (RenderFragment)。 下面的组件参数示例在 Tuple 中传递三个值:
RenderTupleChild.razor:
- Integer: @Data?.Item1
- String: @Data?.Item2
- Boolean: @Data?.Item3
@code {
[Parameter]
public (int, string, bool)? Data { get; set; }
}
RenderTupleParent.razor:
@page "/render-tuple-parent"
Render Tuple Parent Example
@code {
private (int, string, bool) data = new(999, "I aim to misbehave.", true);
}
支持命名元组,如以下示例所示:
NamedTupleChild.razor:
- Integer: @Data?.TheInteger
- String: @Data?.TheString
- Boolean: @Data?.TheBoolean
@code {
[Parameter]
public (int TheInteger, string TheString, bool TheBoolean)? Data { get; set; }
}
NamedTuples.razor:
@page "/named-tuples"
Named Tuples Example
@code {
private (int TheInteger, string TheString, bool TheBoolean) data =
new(999, "I aim to misbehave.", true);
}
引用 ©2005 环球影业:宁静号(内森·菲利安)
组件参数和 Tuples 类型支持 (RenderFragment)。 下面的组件参数示例在 Tuple 中传递三个值:
RenderTupleChild.razor:
- Integer: @Data?.Item1
- String: @Data?.Item2
- Boolean: @Data?.Item3
@code {
[Parameter]
public (int, string, bool)? Data { get; set; }
}
RenderTupleParent.razor:
@page "/render-tuple-parent"
Render Tuple Parent Example
@code {
private (int, string, bool) data = new(999, "I aim to misbehave.", true);
}
支持命名元组,如以下示例所示:
NamedTupleChild.razor:
- Integer: @Data?.TheInteger
- String: @Data?.TheString
- Boolean: @Data?.TheBoolean
@code {
[Parameter]
public (int TheInteger, string TheString, bool TheBoolean)? Data { get; set; }
}
NamedTuples.razor:
@page "/named-tuples"
Named Tuples Example
@code {
private (int TheInteger, string TheString, bool TheBoolean) data =
new(999, "I aim to misbehave.", true);
}
引用 ©2005 环球影业:宁静号(内森·菲利安)
组件参数和 Tuples 类型支持 (RenderFragment)。 下面的组件参数示例在 Tuple 中传递三个值:
RenderTupleChild.razor:
Tuple Card- Integer: @Data?.Item1
- String: @Data?.Item2
- Boolean: @Data?.Item3
@code {
[Parameter]
public (int, string, bool)? Data { get; set; }
}
RenderTupleParent.razor:
@page "/render-tuple-parent"
Render Tuple Parent
@code {
private (int, string, bool) data = new(999, "I aim to misbehave.", true);
}
支持命名元组,如以下示例所示:
RenderNamedTupleChild.razor:
Tuple Card- Integer: @Data?.TheInteger
- String: @Data?.TheString
- Boolean: @Data?.TheBoolean
@code {
[Parameter]
public (int TheInteger, string TheString, bool TheBoolean)? Data { get; set; }
}
RenderNamedTupleParent.razor:
@page "/render-named-tuple-parent"
Render Named Tuple Parent
@code {
private (int TheInteger, string TheString, bool TheBoolean) data =
new(999, "I aim to misbehave.", true);
}
引用 ©2005 环球影业:宁静号(内森·菲利安)
路由参数
组件可以在 @page 指令的路由模板中指定路由参数。
Blazor 路由器使用路由参数来填充相应的组件参数。
RouteParameter1.razor:
@page "/route-parameter-1/{text}"
Route Parameter Example 1
Blazor is @Text!
@code {
[Parameter]
public string? Text { get; set; }
}
@page "/route-parameter-1/{text}"
Route Parameter Example 1
Blazor is @Text!
@code {
[Parameter]
public string? Text { get; set; }
}
@page "/route-parameter-1/{text}"
Blazor is @Text!
@code {
[Parameter]
public string? Text { get; set; }
}
@page "/route-parameter-1/{text}"
Blazor is @Text!
@code {
[Parameter]
public string? Text { get; set; }
}
@page "/route-parameter-1/{text}"
Blazor is @Text!
@code {
[Parameter]
public string Text { get; set; }
}
@page "/route-parameter-1/{text}"
Blazor is @Text!
@code {
[Parameter]
public string Text { get; set; }
}
有关详细信息,请参阅 的Blazor部分。 另外还支持可选路由参数,它们在同一部分中有介绍。 有关捕获跨越多个文件夹边界路径的 catch-all 路由参数 ({*pageRoute}) 的信息,请参阅 中的“Blazor”部分。
有关详细信息,请参阅 的Blazor部分。 不支持可选路由参数,因此需要两个 @page 指令(有关详细信息,请参阅路由参数部分)。 有关捕获跨越多个文件夹边界路径的 catch-all 路由参数 ({*pageRoute}) 的信息,请参阅 中的“Blazor”部分。
警告
使用默认启用的压缩时,避免创建安全(经过身份验证/授权)的交互式服务器端组件来呈现来自不受信任的源的数据。 不受信任的源包括路由参数、查询字符串、来自 JS 互操作的数据,以及第三方用户可以控制的任何其他数据源(数据库、外部服务)。 有关详细信息,请参阅 ASP.NET Core BlazorSignalR 指南和 ASP.NET Core Blazor 交互式服务器端呈现的威胁缓解指南。
子内容呈现片段
组件可以设置另一个组件的内容。 分配组件提供子组件的开始标记与结束标记之间的内容。
在下面的示例中,RenderFragmentChild 组件具有一个 ChildContent 组件参数,它将要呈现的 UI 段表示为 RenderFragment。
ChildContent 在组件 Razor 标记中的位置是在最终 HTML 输出中呈现内容的位置。
RenderFragmentChild.razor:
@code {
[Parameter]
public RenderFragment? ChildContent { get; set; }
}
@code {
[Parameter]
public RenderFragment? ChildContent { get; set; }
}
@code {
[Parameter]
public RenderFragment? ChildContent { get; set; }
}
@code {
[Parameter]
public RenderFragment? ChildContent { get; set; }
}
@code {
[Parameter]
public RenderFragment ChildContent { get; set; }
}
@code {
[Parameter]
public RenderFragment ChildContent { get; set; }
}
重要
必须按约定将接收 RenderFragment 内容的属性命名为 ChildContent。
不支持RenderFragment。
以下组件通过将内容置于子组件的开始标记和结束标记内,来提供用于呈现 RenderFragmentChild 的内容。
RenderFragments.razor:
@page "/render-fragments"
Render Fragments Example
Content of the child component is supplied
by the parent component.
RenderFragments.razor:
@page "/render-fragments"
Render Fragments Example
Content of the child component is supplied
by the parent component.
RenderFragmentParent.razor:
@page "/render-fragment-parent"
Render child content
Content of the child component is supplied
by the parent component.
RenderFragmentParent.razor:
@page "/render-fragment-parent"
Render child content
Content of the child component is supplied
by the parent component.
RenderFragmentParent.razor:
@page "/render-fragment-parent"
Render child content
Content of the child component is supplied
by the parent component.
RenderFragmentParent.razor:
@page "/render-fragment-parent"
Render child content
Content of the child component is supplied
by the parent component.
呈现片段用于在整个 Blazor 应用中呈现子内容,在下面的文章和文章部分中有示例介绍:
Blazor 布局
跨组件层次结构传递数据
模板化组件
全局异常处理
说明
Blazor 框架的内置 Razor 组件使用相同的 ChildContent 组件参数约定来设置其内容。 您可以在 ChildContent中通过搜索组件参数属性名称 来查看设置子内容的组件(使用搜索词 "ChildContent" 过滤 API)。
可重用呈现逻辑的呈现片段
你可以分解出子组件,纯粹作为重复使用呈现逻辑的方法。 在任何组件的 @code 块中,定义 RenderFragment,并可以根据需要从任意位置多次呈现该片段。
@RenderWelcomeInfo
Render the welcome info a second time:
@RenderWelcomeInfo
@code {
private RenderFragment RenderWelcomeInfo = @
Welcome to your new app!
;}
有关更多信息,请参阅重用渲染逻辑。
带有组件参数和子内容的循环变量
如果递增循环变量由组件的参数或 for 子内容使用,则呈现 RenderFragment 循环内的组件需要一个局部索引变量。
请考虑以下 RenderFragmentChild2 组件,该组件同时具有组件参数 (Id) 和用于显示子内容的呈现片段 (ChildContent)。
RenderFragmentChild2.razor:
@code {
[Parameter]
public string? Id { get; set; }
[Parameter]
public RenderFragment? ChildContent { get; set; }
}
如果在父组件中呈现 RenderFragmentChild2 组件,在分配组件参数值并提供子组件的内容时,请使用本地索引变量(下面示例中的 ct)而不是循环变量 (c):
@for (int c = 1; c < 4; c++)
{
var ct = c;
Count: @ct
}
或者,将 foreach 循环与 Enumerable.Range 结合使用,而不是使用 for 循环:
@foreach (var c in Enumerable.Range(1, 3))
{
Count: @c
}
捕获对组件的引用
组件引用提供了一种引用组件实例以便发出命令的方法。 若要捕获组件引用,请执行以下操作:
向子组件添加 @ref 特性。
定义与子组件类型相同的字段。
呈现组件时,将用组件实例填充字段。 然后,可以在实例上调用 .NET 方法。
请考虑以下 ReferenceChild 组件,它会在调用其 ChildMethod 时记录消息。
ReferenceChild.razor:
@inject ILogger
@if (value > 0)
{
value: @value
}
@code {
private int value;
public void ChildMethod(int value)
{
Logger.LogInformation("Received {Value} in ChildMethod", value);
this.value = value;
StateHasChanged();
}
}
@inject ILogger
@if (value > 0)
{
value: @value
}
@code {
private int value;
public void ChildMethod(int value)
{
Logger.LogInformation("Received {Value} in ChildMethod", value);
this.value = value;
StateHasChanged();
}
}
@using Microsoft.Extensions.Logging
@inject ILogger
@code {
public void ChildMethod(int value)
{
Logger.LogInformation("Received {Value} in ChildMethod", value);
}
}
@using Microsoft.Extensions.Logging
@inject ILogger
@code {
public void ChildMethod(int value)
{
Logger.LogInformation("Received {Value} in ChildMethod", value);
}
}
@using Microsoft.Extensions.Logging
@inject ILogger
@code {
public void ChildMethod(int value)
{
Logger.LogInformation("Received {Value} in ChildMethod", value);
}
}
@using Microsoft.Extensions.Logging
@inject ILogger
@code {
public void ChildMethod(int value)
{
Logger.LogInformation("Received {Value} in ChildMethod", value);
}
}
组件引用仅在呈现组件后才进行填充,其输出包含 ReferenceChild 的元素。 在呈现组件之前,没有任何可引用的内容。 请勿尝试直接将引用的组件方法调用事件处理程序(例如 @onclick="childComponent!.ChildMethod(5)"),因为在分配单击事件时可能不会分配引用变量。
若要在组件完成呈现后操作组件引用,请使用 OnAfterRender 或 OnAfterRenderAsync 方法。
以下示例使用了前面的 ReferenceChild 组件。
ReferenceParent.razor:
@page "/reference-parent"
Call ReferenceChild.ChildMethod (first instance)
with an argument of 5
Call ReferenceChild.ChildMethod (second instance)
with an argument of 5
@code {
private ReferenceChild? childComponent1;
private ReferenceChild? childComponent2;
private void CallChildMethod() => childComponent2!.ChildMethod(5);
}
@page "/reference-parent"
Call ReferenceChild.ChildMethod (first instance)
with an argument of 5
Call ReferenceChild.ChildMethod (second instance)
with an argument of 5
@code {
private ReferenceChild? childComponent1;
private ReferenceChild? childComponent2;
private void CallChildMethod() => childComponent2!.ChildMethod(5);
}
@page "/reference-parent"
Call ReferenceChild.ChildMethod (first instance)
with an argument of 5
Call ReferenceChild.ChildMethod (second instance)
with an argument of 5
@code {
private ReferenceChild? childComponent1;
private ReferenceChild? childComponent2;
private void CallChildMethod()
{
childComponent2!.ChildMethod(5);
}
}
@page "/reference-parent"
Call ReferenceChild.ChildMethod (first instance)
with an argument of 5
Call ReferenceChild.ChildMethod (second instance)
with an argument of 5
@code {
private ReferenceChild? childComponent1;
private ReferenceChild? childComponent2;
private void CallChildMethod()
{
childComponent2!.ChildMethod(5);
}
}
@page "/reference-parent"
Call ReferenceChild.ChildMethod (first instance)
with an argument of 5
Call ReferenceChild.ChildMethod (second instance)
with an argument of 5
@code {
private ReferenceChild childComponent1;
private ReferenceChild childComponent2;
private void CallChildMethod()
{
childComponent2!.ChildMethod(5);
}
}
@page "/reference-parent"
Call ReferenceChild.ChildMethod (first instance)
with an argument of 5
Call ReferenceChild.ChildMethod (second instance)
with an argument of 5
@code {
private ReferenceChild childComponent1;
private ReferenceChild childComponent2;
private void CallChildMethod()
{
childComponent2!.ChildMethod(5);
}
}
尽管捕获组件引用使用与捕获元素引用类似的语法,但捕获组件引用不是 JavaScript 互操作功能。 组件引用不会传递给 JavaScript 代码。 组件引用只在 .NET 代码中使用。
重要
不要使用组件引用来改变子组件的状态。 请改用常规声明性组件参数将数据传递给子组件。 使用组件参数使子组件在正确的时间自动重新呈现。 有关详细信息,请参阅组件参数部分和 ASP.NET Core Blazor 数据绑定一文。
应用一个属性
可以通过 @attribute 指令将特性应用于组件。 下面的示例将 [Authorize] 特性应用于组件的类:
@page "/"
@attribute [Authorize]
条件性的 HTML 元素的属性和 DOM 属性
Blazor 采用以下常规行为:
对于 HTML 属性,Blazor 根据 .NET 值有条件地设置或移除属性。 如果 .NET 值为 false 或 null,则不会设置或移除该属性(如果之前已设置该属性)。
对于 DOM 属性(例如 checked 或 value),Blazor 会基于 .NET 值设置 DOM 属性。 如果 .NET 值为 false 或 null,则 DOM 属性将重置为默认值。
哪些 Razor 语法特性对应于 HTML 特性,哪些对应于 DOM 属性仍然没有记录,因为这是一个框架实现细节,可能会在不通知的情况下发生更改。
警告
某些 HTML 属性(例如 aria-pressed)必须具有字符串值“true”或“false”。 由于它们需要字符串值而不是布尔值,因此必须使用 .NET string 而非使用 bool 作为其值。 这是由浏览器 DOM API 设置的要求。
原始 HTML
通常使用 DOM 文本节点呈现字符串,这意味着将忽略它们可能包含的任何标记,并将其视为文字文本。 若要呈现原始 HTML,请将 HTML 内容包装在 MarkupString 值中。 将该值分析为 HTML 或 SVG,并插入到 DOM 中。
警告
呈现由任何不受信任的源生成的原始 HTML 是一个安全风险,应始终避免。
下面的示例演示如何使用 MarkupString 类型向组件的呈现输出添加静态 HTML 内容块。
MarkupStrings.razor:
@page "/markup-strings"
Markup Strings Example
@((MarkupString)myMarkup)
@code {
private string myMarkup =
"
This is a dangerous markup string.
";}
MarkupStrings.razor:
@page "/markup-strings"
Markup Strings Example
@((MarkupString)myMarkup)
@code {
private string myMarkup =
"
This is a dangerous markup string.
";}
MarkupStringExample.razor:
@page "/markup-string-example"
@((MarkupString)myMarkup)
@code {
private string myMarkup =
"
This is a dangerous markup string.
";}
MarkupStringExample.razor:
@page "/markup-string-example"
@((MarkupString)myMarkup)
@code {
private string myMarkup =
"
This is a dangerous markup string.
";}
MarkupStringExample.razor:
@page "/markup-string-example"
@((MarkupString)myMarkup)
@code {
private string myMarkup =
"
This is a dangerous markup string.
";}
MarkupStringExample.razor:
@page "/markup-string-example"
@((MarkupString)myMarkup)
@code {
private string myMarkup =
"
This is a dangerous markup string.
";}
Razor 模板
可以使用 Razor 模板语法定义呈现片段,从而定义 UI 片段。
Razor 模板使用以下格式:
@<{HTML tag}>...{HTML tag}>
下面的示例演示如何在组件中指定 RenderFragment 和 RenderFragment
RazorTemplate.razor:
@page "/razor-template"
Razor Template Example
@timeTemplate
@petTemplate(new Pet { Name = "Nutty Rex" })
@code {
private RenderFragment timeTemplate = @
The time is @DateTime.Now.
;private RenderFragment Pet: @pet.Name
private class Pet
{
public string? Name { get; set; }
}
}
@page "/razor-template"
Razor Template Example
@timeTemplate
@petTemplate(new Pet { Name = "Nutty Rex" })
@code {
private RenderFragment timeTemplate = @
The time is @DateTime.Now.
;private RenderFragment Pet: @pet.Name
private class Pet
{
public string? Name { get; set; }
}
}
@page "/razor-template"
@timeTemplate
@petTemplate(new Pet { Name = "Nutty Rex" })
@code {
private RenderFragment timeTemplate = @
The time is @DateTime.Now.
;private RenderFragment Pet: @pet.Name
private class Pet
{
public string? Name { get; set; }
}
}
@page "/razor-template"
@timeTemplate
@petTemplate(new Pet { Name = "Nutty Rex" })
@code {
private RenderFragment timeTemplate = @
The time is @DateTime.Now.
;private RenderFragment Pet: @pet.Name
private class Pet
{
public string? Name { get; set; }
}
}
@page "/razor-template"
@timeTemplate
@petTemplate(new Pet { Name = "Nutty Rex" })
@code {
private RenderFragment timeTemplate = @
The time is @DateTime.Now.
;private RenderFragment Pet: @pet.Name
private class Pet
{
public string Name { get; set; }
}
}
@page "/razor-template"
@timeTemplate
@petTemplate(new Pet { Name = "Nutty Rex" })
@code {
private RenderFragment timeTemplate = @
The time is @DateTime.Now.
;private RenderFragment Pet: @pet.Name
private class Pet
{
public string Name { get; set; }
}
}
以上代码的呈现输出:
The time is 4/19/2021 8:54:46 AM.
Pet: Nutty Rex
静态资产
Blazor 遵循 ASP.NET Core 应用对于静态资产的约定。 静态资产位于项目的 web root (wwwroot) 文件夹中或是 wwwroot 文件夹下的文件夹中。
使用基相对路径 (/) 来引用静态资产的 Web 根。 在下面的示例中,logo.png 实际位于 {PROJECT ROOT}/wwwroot/images 文件夹中。
{PROJECT ROOT} 是应用的项目根。

组件不支持波浪符斜杠表示法 (~/)。
有关设置应用基路径的信息,请参阅 ASP.NET 核心 Blazor 应用基路径。
组件中不支持标记帮助程序
组件中不支持 Tag Helpers。 若要在 Blazor 中提供类似标记帮助程序的功能,请创建一个具有与标记帮助程序相同功能的组件,并改为使用该组件。
可缩放的向量图形 (SVG) 图像
由于 Blazor 呈现 HTML,因此通过 .svg 标记支持浏览器支持的图像,包括:
同样,样式表文件 (.css) 的 CSS 规则支持 SVG 图像:
.element-class {
background-image: url("image.svg");
}
Blazor 支持 
下面的示例展示了如何:
string (@message) 的显示情况。
具有 元素和 value 字段的双向绑定。
Robot 组件。
fill="none" /> @message
Two-way binding:
@code {
private string message = "Lorem ipsum dolor sit amet, consectetur adipiscing " +
"elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";
private string? value;
}
空白的呈现行为
除非将 @preservewhitespace 指令与值 true 一起使用,否则在以下情况下将删除额外空格:
元素中的前导或尾随空白。
RenderFragment
/
RenderFragment
它出现在 C# 代码块(例如 @if 或 @foreach)之前或之后。
但是,在使用 CSS 规则(例如 white-space: pre)时,删除空白可能会影响呈现输出。 若要禁用此性能优化并保留空白,请执行以下任一操作:
将 @preservewhitespace true 指令添加到 Razor 文件 (.razor) 的顶部,从而将首选项应用于特定组件。
将 @preservewhitespace true 指令添加到 _Imports.razor 文件中,从而将首选项应用于子目录或整个项目。
在大多数情况下,不需要执行任何操作,因为应用程序通常会继续正常运行(但速度会更快)。 如果去除空白会导致特定组件出现呈现问题,请在该组件中使用 @preservewhitespace true 来禁用此优化。
空白将保留在组件的源标记中。 即使在没有视觉效果的情况下,只有空白的文本也会呈现在浏览器的 DOM 中。
请考虑以下组件标记:
- 
@item.Text 
@foreach (var item in Items)
{
}
前面的示例呈现以下不必要的空白:
在 @foreach 代码块外。
围绕
围绕 @item.Text 输出。
100 项的列表会导致超过 400 个空白区域。 任何额外空白都不会在视觉上影响呈现的输出。
呈现组件的静态 HTML 时,不会保留标记中的空白。 例如,查看组件  文件 (Razor) 中以下 .razor 标记的呈现输出:

不会保留前面标记中的空白:

根组件
根 Razor 组件(根组件)是加载应用创建的任何组件层次结构的第一个组件。
在从 Blazor Web App 项目模板创建的应用中,由服务器端 App 文件中调用 App.razor 时所声明的类型参数指定 MapRazorComponents
app.MapRazorComponents
说明
不支持让根组件具有交互性(例如 App 组件)。
在使用Blazor Server项目模板创建的应用中,使用App组件标签帮助器将App.razor组件(Pages/_Host.cshtml)指定为中的默认根组件。
在从 Blazor WebAssembly 项目模板创建的应用中,将 App 组件 (App.razor) 指定为 Program 文件中的默认根组件:
builder.RootComponents.Add
在前面的代码中,CSS 选择器 #app 指示为 App 中的
MVC 和 Razor Pages 应用还可以使用组件标记帮助程序来注册静态呈现的 Blazor WebAssembly 根组件:
静态呈现的组件只能添加到应用。 之后无法移除或更新它们。
有关更多信息,请参见以下资源:
ASP.NET Core 中的组件标记帮助程序
将 ASP.NET 核心 Razor 组件与 MVC 或 Razor Pages 集成
