添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

此信息与预发布产品相关,相应产品在商业发布之前可能会进行重大修改。 Microsoft 对此处提供的信息不提供任何明示或暗示的保证。

对于当前版本,请参阅 本文的 .NET 7 版本

本文介绍如何在 Blazor 应用中创建和使用 Razor 组件,包括有关 Razor 语法、组件命名、命名空间和组件参数的指导。

Blazor 应用是使用 Razor 组件 (非正式地称为 Blazor 组件 组件 )构建的。 组件是用户界面 (UI) 的自包含部分,具有用于启用动态行为的处理逻辑。 组件可以嵌套、重复使用、在项目间共享,并可 在 MVC 和 Razor Pages 应用中使用

组件是使用 C# 和 HTML 标记的组合在 Razor 组件文件(文件扩展名为 .razor )中实现的。

默认情况下, ComponentBase 是 Razor 组件文件描述的组件的基类。 ComponentBase 实现组件的最低抽象, IComponent 接口。 ComponentBase 定义基本功能的组件属性和方法,例如,处理一组内置组件生命周期事件。

dotnet/aspnetcore 引用源中的 ComponentBase :引用源包含有关内置生命周期事件的其他注释。 但是请记住,组件功能的内部实现随时可能会更改,但不会发出通知。

指向 .NET 参考源的文档链接通常会加载存储库的默认分支,该分支表示针对下一个 .NET 版本的当前开发。 若要为特定版本选择标记,请使用“切换分支或标记”下拉列表。 有关详细信息,请参阅 如何选择 ASP.NET Core 源代码的版本标记 (dotnet/AspNetCore.Docs #26205)

开发人员通常从 Razor 组件文件 ( .razor ) 创建 Razor 组件,或将组件构建于 ComponentBase 之上,但组件也可以通过实现 IComponent 来生成。 实现 IComponent 的开发人员所构建的组件可以对呈现采用低级别控制,代价是需要使用事件和生命周期方法手动触发呈现,且这些事件和方法必须由开发人员创建和维护。

Razor 语法

组件使用 Razor 语法 。 组件广泛使用了两个 Razor 功能,即指令和指令特性 。 这两个功能是前缀为 @ 的保留关键字,出现在 Razor 标记中:

  • 指令 :更改组件标记的分析或运行方式。 例如, @page 指令使用路由模板指定可路由组件,可以由用户请求在浏览器中按特定 URL 直接访问。
  • 指令特性 :更改组件元素的分析方式或运行方式。 例如, <input> 元素的 @bind 指令特性会将数据绑定到元素的值。
  • 本文和 Blazor 文档集的其他文章中进一步说明了在组件中使用的指令和指令特性。 有关 Razor 语法的一般信息,请参阅 ASP.NET Core 的 Razor 语法参考

    组件名称、类名和命名空间

    组件的名称必须以大写字符开头:

    支持: ProductDetail.razor

    不支持: productDetail.razor

    整个 Blazor 文档中使用的常见 Blazor 命名约定包括:

  • 文件路径和文件名使用 †Pascal 大小写,且在显示组件代码示例之前出现。 如果路径存在,则表示典型的文件夹位置。 例如, Components/Pages/ProductDetail.razor 表示 ProductDetail 组件具有文件名 ProductDetail.razor ,并位于应用的 Components 文件夹的 Pages 文件夹中。
  • 可路由组件的组件文件路径与其 ‡kebab 大小写形式的 URL 匹配,组件路由模板中各单词之间会显示连字符。 例如,在浏览器中,通过相对 URL /product-detail 请求具有路由模板 /product-detail ( @page "/product-detail" ) 的 ProductDetail 组件。
  • †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
    

    _Imports.razor 文件中的 @using 指令仅适用于 Razor 文件 (.razor),而不适用于 C# 文件 (.cs)。

    不支持使用别名的 using 语句。 在以下示例中,GridRendering 组件的公共 WeatherForecast 类作为应用其他位置的组件中的 WeatherForecast 提供:

    @using WeatherForecast = Components.Pages.GridRendering.WeatherForecast
    

    还可以使用其完全限定的名称来引用组件,这时不需要 @using 指令。 以下示例直接引用应用的 AdminComponents/Pages 文件夹中的 ProductDetail 组件:

    <BlazorSample.AdminComponents.Pages.ProductDetail />
    

    使用 Razor 创建的组件的命名空间基于以下内容(按优先级顺序):

  • Razor 文件标记中的 @namespace 指令(例如 @namespace BlazorSample.CustomNamespace)。
  • 项目文件中项目的 RootNamespace(例如 <RootNamespace>BlazorSample</RootNamespace>)。
  • 项目命名空间和从项目根目录到组件的路径。 例如,框架将具有项目命名空间 BlazorSample{PROJECT NAMESPACE}/Components/Pages/Home.razor 解析到 Home 组件的命名空间 BlazorSample.Components.Pages{PROJECT NAMESPACE} 为项目命名空间。 组件遵循 C# 名称绑定规则。 对于本示例中的 Home 组件,范围内的组件是所有组件:
    • 在同一文件夹 Components/Pages 中。
    • 未显式指定其他命名空间的项目根中的组件。
    • 不支持以下项目

    • global:: 限定。
    • 部分限定的名称。 例如,无法将 @using BlazorSample 添加到组件中,然后使用 <Layout.NavMenu></Layout.NavMenu> 在应用的 Components/Layout 文件夹中引用 NavMenu 组件 (Components/Layout/NavMenu.razor)。
    • 组件的名称必须以大写字符开头:

      支持:ProductDetail.razor

      不支持:productDetail.razor

      整个 Blazor 文档中使用的常见 Blazor 命名约定包括:

    • 文件路径和文件名使用 †Pascal 大小写,且在显示组件代码示例之前出现。 如果路径存在,则表示典型的文件夹位置。 例如,Pages/ProductDetail.razor 指示 ProductDetail 组件具有文件名 ProductDetail.razor,并位于应用的 Pages 文件夹中。
    • 可路由组件的组件文件路径与其 ‡kebab 大小写形式的 URL 匹配,组件路由模板中各单词之间会显示连字符。 例如,在浏览器中,通过相对 URL /product-detail 请求具有路由模板 /product-detail (@page "/product-detail") 的 ProductDetail 组件。
    • †Pascal 大小写(大写 camel 形式)是不带空格和标点符号的命名约定,其中每个单词的首字母大写(包括第一个单词)。
      ‡Kebab 大小写是一种命名约定,不使用空格和标点符号,它使用小写字母,且单词之间有短划线。

      组件是普通 C# 类,可以放置在项目中的任何位置。 生成网页的组件通常位于 Pages 文件夹中。 非页面组件通常放置在 Shared 文件夹或添加到项目的自定义文件夹中。

      通常,组件的命名空间是从应用的根命名空间和该组件在应用内的位置(文件夹)派生而来的。 如果应用的根命名空间是 BlazorSample,并且 Counter 组件位于 Pages 文件夹中:

    • Counter 组件的命名空间为 BlazorSample.Pages
    • 组件的完全限定类型名称为 BlazorSample.Pages.Counter
    • 对于保存组件的自定义文件夹,将 @using 指令添加到父组件或应用的 _Imports.razor 文件。 下面的示例提供 AdminComponents 文件夹中的组件:

      @using BlazorSample.AdminComponents
      

      _Imports.razor 文件中的 @using 指令仅适用于 Razor 文件 (.razor),而不适用于 C# 文件 (.cs)。

      不支持使用别名的 using 语句。 在以下示例中,GridRendering 组件的公共 WeatherForecast 类作为应用其他位置的组件中的 WeatherForecast 提供:

      @using WeatherForecast = Pages.GridRendering.WeatherForecast
      

      还可以使用其完全限定的名称来引用组件,这时不需要 @using 指令。 以下示例直接引用应用的 Components 文件夹中的 ProductDetail 组件:

      <BlazorSample.Components.ProductDetail />
      

      使用 Razor 创建的组件的命名空间基于以下内容(按优先级顺序):

    • Razor 文件标记中的 @namespace 指令(例如 @namespace BlazorSample.CustomNamespace)。
    • 项目文件中项目的 RootNamespace(例如 <RootNamespace>BlazorSample</RootNamespace>)。
    • 项目命名空间和从项目根目录到组件的路径。 例如,框架将具有项目命名空间 BlazorSample{PROJECT NAMESPACE}/Pages/Index.razor 解析到 Index 组件的命名空间 BlazorSample.Pages{PROJECT NAMESPACE} 为项目命名空间。 组件遵循 C# 名称绑定规则。 对于本示例中的 Index 组件,范围内的组件是所有组件:
      • 在同一文件夹 Pages 中。
      • 未显式指定其他命名空间的项目根中的组件。
      • 不支持以下项目

      • global:: 限定。
      • 部分限定的名称。 例如,无法将 @using BlazorSample 添加到组件中,然后使用 <Shared.NavMenu></Shared.NavMenu> 在应用的 Shared 文件夹中引用 NavMenu 组件 (Shared/NavMenu.razor)。
      • 分部类支持

        组件以 C# 分部类的形式生成,使用以下任一方法进行创作:

      • 单个文件包含在一个或多个 @code 块、HTML 标记和 Razor 标记中定义的 C# 代码。 Blazor 项目模板使用此单文件方法来定义其组件。
      • HTML 和 Razor 标记位于 Razor 文件 (.razor) 中。 C# 代码位于定义为分部类的代码隐藏文件 (.cs) 中。
      • 定义特定于组件的样式的组件样式表是单独的文件 (.css)。 Blazor CSS 隔离稍后在 ASP.NET Core Blazor CSS 隔离 中进行介绍。

        下面的示例显示了从 Blazor 项目模板生成的应用中具有 @code 块的默认 Counter 组件。 标记和 C# 代码位于同一个文件中。 这是在创作组件时采用的最常见方法。

        Counter.razor

        @page "/counter" <PageTitle>Counter</PageTitle> <h1>Counter</h1> <p role="status">Current count: @currentCount</p> <button class="btn btn-primary" @onclick="IncrementCount">Click me</button> @code { private int currentCount = 0; private void IncrementCount() currentCount++; <p role="status">Current count: @currentCount</p> <button class="btn btn-primary" @onclick="IncrementCount">Click me</button> @code { private int currentCount = 0; private void IncrementCount() currentCount++; <p>Current count: @currentCount</p> <button class="btn btn-primary" @onclick="IncrementCount">Click me</button> @code { private int currentCount = 0; private void IncrementCount() currentCount++; <p>Current count: @currentCount</p> <button class="btn btn-primary" @onclick="IncrementCount">Click me</button> @code { private int currentCount = 0; private void IncrementCount() currentCount++;

        以下 Counter 组件使用带有分部类的代码隐藏文件从 C# 代码中拆分呈现 HTML 和 Razor 标记。 一些组织和开发人员倾向于从 C# 代码拆分标记,借此组织其组件代码来适应他们偏好的工作方式。 例如,组织的 UI 专家可以独自处理呈现层,而不必依赖处理组件的 C# 逻辑的另一位开发人员。 使用自动生成的代码或源生成器时,此方法也很有用。 有关详细信息,请参阅分部类和方法(C# 编程指南)

        CounterPartialClass.razor

        @page "/counter-partial-class" <PageTitle>Counter</PageTitle> <h1>Counter</h1> <p role="status">Current count: @currentCount</p> <button class="btn btn-primary" @onclick="IncrementCount">Click me</button> <p>Current count: @currentCount</p> <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

        CounterPartialClass.razor.cs

        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++;
        

        _Imports.razor 文件中的 @using 指令仅适用于 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 Microsoft.AspNetCore.Components.Web.Virtualization;
        using Microsoft.JSInterop;
        

        典型命名空间还包含应用的命名空间以及与应用的 Components 文件夹对应的命名空间:

        using BlazorSample;
        using BlazorSample.Components;
        
        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 中的继承

        在下面的示例中,BlazorRocksBase 基类派生自 ComponentBase

        BlazorRocks.razor

        @page "/blazor-rocks" @inherits BlazorRocksBase <h1>@BlazorRocksText</h1> public class BlazorRocksBase : ComponentBase public string BlazorRocksText { get; set; } = "Blazor rocks the browser!"; public class BlazorRocksBase : ComponentBase public string BlazorRocksText { get; set; } = "Blazor rocks the browser!"; public class BlazorRocksBase : ComponentBase public string BlazorRocksText { get; set; } = "Blazor rocks the browser!"; public class BlazorRocksBase : ComponentBase public string BlazorRocksText { get; set; } = "Blazor rocks the browser!";

        可以通过使用 @page 指令为应用中的每个可访问组件提供路由模板来实现 Blazor 中的路由。 编译具有 @page 指令的 Razor 文件时,将为生成的类提供指定路由模板的 RouteAttribute。 在运行时,路由器将使用 RouteAttribute 搜索组件类,并呈现具有与请求的 URL 匹配的路由模板的任何组件。

        以下 HelloWorld 组件使用 /hello-world的路由模板,并且组件的呈现网页在相对 URL /hello-world 到达。

        HelloWorld.razor

        @page "/hello-world" <h1>Hello World!</h1>

        前面的组件在浏览器中通过 /hello-world 进行加载,无论是否将组件添加到应用的 UI 导航。 (可选)组件可以添加到 NavMenu 组件,以便在应用基于 UI 的导航中显示组件链接。

        对于前面的 HelloWorld 组件,可以将 NavLink 组件添加到 NavMenu 组件。 有关详细信息(包括对 NavLinkNavMenu 组件的描述),请参阅 ASP.NET Core Blazor 路由和导航

        组件的 UI 使用由 Razor 标记、C# 和 HTML 组成的 Razor 语法进行定义。 在编译应用时,HTML 标记和 C# 呈现逻辑转换为组件类。 生成的类的名称与文件名匹配。

        组件类的成员在一个或多个 @code 块中定义。 在 @code 块中,组件状态使用 C# 进行指定和处理:

      • 属性和字段初始化表达式。
      • 由父组件和路由参数传递的自变量的参数值。
      • 用于用户事件处理、生命周期事件和自定义组件逻辑的方法。
      • 组件成员使用以 @ 符号开头的 C# 表达式在呈现逻辑中进行使用。 例如,通过为字段名称添加 @ 前缀来呈现 C# 字段。 下面 Markup 示例计算并呈现:

      • headingFontStyle,表示标题元素的 CSS 属性值 font-style
      • headingText,表示标题元素的内容。
      • Markup.razor

        @page "/markup" <h1 style="font-style:@headingFontStyle">@headingText</h1> @code { private string headingFontStyle = "italic"; private string headingText = "Put on your new Blazor!"; @code { private string headingFontStyle = "italic"; private string headingText = "Put on your new Blazor!"; @code { private string headingFontStyle = "italic"; private string headingText = "Put on your new Blazor!"; @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)。 属性名称需要大写(示例:LayoutComponentBase.Body@Body)。

        异步方法 (async) 不支持返回 void

        Blazor 框架不跟踪返回 void 的异步方法 (async)。 因此,如果 void 返回,则不会捕获异常。 始终从异步方法返回 Task

        通过使用 HTML 语法声明组件,组件可以包含其他组件。 使用组件的标记类似于 HTML 标记,其中标记的名称是组件类型。

        请考虑以下 Heading 组件,其他组件可以使用该组件显示标题。

        Heading.razor

        <h1 style="font-style:@headingFontStyle">Heading Example</h1> @code { private string headingFontStyle = "italic";

        如果某个组件包含一个 HTML 元素,该元素的大写首字母与相同命名空间中的组件名称不匹配,则会发出警告,指示该元素名称异常。 为组件的命名空间添加 @using 指令使组件可用,这可解决此警告。 有关详细信息,请参阅组件名称、类名和命名空间部分。

        此部分中显示的 Heading 组件示例没有 @page 指令,因此用户无法在浏览器中通过直接请求直接访问 Heading 组件。 但是,具有 @page 指令的任何组件都可以嵌套在另一个组件中。 如果通过在 Razor 文件顶部包含 @page "/heading" 可直接访问 Heading组件,则会在 /heading/heading-example 处为浏览器请求呈现该组件。

        组件参数将数据传递给组件,使用组件类中包含 [Parameter] 特性的公共 C# 属性进行定义。 在下面的示例中,内置引用类型 (System.String) 和用户定义的引用类型 (PanelBody) 作为组件参数进行传递。

        PanelBody.cs

        public class PanelBody public string? Text { get; set; } public string? Style { get; set; } <div class="card w-25" style="margin-bottom:15px"> <div class="card-header font-weight-bold">@Title</div> <div class="card-body" style="font-style:@Body.Style"> @Body.Text @code { [Parameter] public string Title { get; set; } = "Set By Child"; [Parameter] public PanelBody Body { get; set; } = new() Text = "Set by child.", Style = "normal" <div class="card w-25" style="margin-bottom:15px"> <div class="card-header font-weight-bold">@Title</div> <div class="card-body" style="font-style:@Body.Style"> @Body.Text @code { [Parameter] public string Title { get; set; } = "Set By Child"; [Parameter] public PanelBody Body { get; set; } = new() Text = "Set by child.", Style = "normal" <div class="card w-25" style="margin-bottom:15px"> <div class="card-header font-weight-bold">@Title</div> <div class="card-body" style="font-style:@Body.Style"> @Body.Text @code { [Parameter] public string Title { get; set; } = "Set By Child"; [Parameter] public PanelBody Body { get; set; } = new() Text = "Set by child.", Style = "normal" <div class="card w-25" style="margin-bottom:15px"> <div class="card-header font-weight-bold">@Title</div> <div class="card-body" style="font-style:@Body.Style"> @Body.Text @code { [Parameter] public string Title { get; set; } = "Set By Child"; [Parameter] public PanelBody Body { get; set; } = new PanelBody() Text = "Set by child.", Style = "normal"

        支持为组件参数提供初始值,但不会创建在首次呈现后向自身参数写入的组件。 有关详细信息,请参阅避免覆盖 ASP.NET Core Blazor 中的参数

        ParameterChild 组件的 TitleBody 组件参数通过自变量在呈现组件实例的 HTML 标记中进行设置。 以下 ParameterParent 组件会呈现两个 ParameterChild 组件:

      • 第一个 ParameterChild 组件在呈现时不提供参数自变量。
      • 第二个 ParameterChild 组件从 ParameterParent 组件接收 TitleBody 的值,后者使用显式 C# 表达式设置 PanelBody 的属性值。
      • ParameterParent.razor

        @page "/parameter-parent" <h1>Child component (without attribute values)</h1> <ParameterChild /> <h1>Child component (with attribute values)</h1> <ParameterChild Title="Set by Parent" Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" /> <ParameterChild Title="Set by Parent" Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" />

        ParameterParent 组件未提供组件参数值时,来自 ParameterParent 组件的以下呈现 HTML 标记会显示 ParameterChild 组件默认值。 当 ParameterParent 组件提供组件参数值时,它们会替换 ParameterChild 组件的默认值。

        为清楚起见,呈现 CSS 样式类未显示在以下呈现 HTML 标记中。

        <h1>Child component (without attribute values)</h1>
            <div>Set By Child</div>
            <div>Set by child.</div>
        <h1>Child component (with attribute values)</h1>
            <div>Set by Parent</div>
            <div>Set by parent.</div>
        

        将方法的 C# 字段、属性或结果作为 HTML 特性值分配给组件参数。 特性的值通常可以是与参数类型匹配的任何 C# 表达式。 特性的值可以选择以 Razor 保留 @ 符号开头,但不是必需的。

        如果组件参数的类型为字符串,则默认情况下会将特性值视为 C# 字符串字面量。 如果要改为指定 C# 表达式,请使用 @ 前缀。

        以下 ParameterParent2 组件显示前面 ParameterChild 组件的四个实例,并将其 Title 参数值设置为:

      • title 字段的值。
      • GetTitle C# 方法的结果。
      • 带有ToLongDateString 的长格式当前本地日期,使用隐式 C# 表达式
      • panelData 对象的 Title 属性。
      • 我们不建议对文本(例如,布尔值)、关键字(例如,this)或 null 使用 @ 前缀,但可以根据需要选择使用它们。 例如,IsFixed="@true" 不常见,但受支持。

        在大多数情况下,根据 HTML5 规范,参数属性值的引号是可选的。 例如,支持 Value=this,而不是 Value="this"。 但是,我们建议使用引号,因为它更易于记住,并且在基于 Web 的技术中被广泛采用。

        在整个文档中,代码示例:

      • 始终使用引号。 示例:Value="this"
      • 非文本则使用 @ 前缀,尽管这是可选操作。 示例:Count="@ct",其中 ct 是数字类型的变量。 Count="ct" 是一种有效的风格方法,但文档和示例不采用约定。
      • 对于 Razor 表达式之外的文本始终避免使用 @。 示例:IsFixed="true"
      • ParameterParent2.razor

        @page "/parameter-parent-2" <ParameterChild Title="@title" /> <ParameterChild Title="@GetTitle()" /> <ParameterChild Title="@DateTime.Now.ToLongDateString()" /> <ParameterChild Title="@panelData.Title" /> @code { private string title = "From Parent field"; private PanelData panelData = new(); private string GetTitle() return "From Parent method"; private class PanelData public string Title { get; set; } = "From Parent object"; <ParameterChild Title="@GetTitle()" /> <ParameterChild Title="@DateTime.Now.ToLongDateString()" /> <ParameterChild Title="@panelData.Title" /> @code { private string title = "From Parent field"; private PanelData panelData = new(); private string GetTitle() return "From Parent method"; private class PanelData public string Title { get; set; } = "From Parent object"; <ParameterChild Title="@GetTitle()" /> <ParameterChild Title="@DateTime.Now.ToLongDateString()" /> <ParameterChild Title="@panelData.Title" /> @code { private string title = "From Parent field"; private PanelData panelData = new(); private string GetTitle() return "From Parent method"; private class PanelData public string Title { get; set; } = "From Parent object"; <ParameterChild Title="@GetTitle()" /> <ParameterChild Title="@DateTime.Now.ToLongDateString()" /> <ParameterChild Title="@panelData.Title" /> @code { private string title = "From Parent field"; private PanelData panelData = new PanelData(); private string GetTitle() return "From Parent method"; private class PanelData public string Title { get; set; } = "From Parent object";

        将 C# 成员分配给组件参数时,不要使用 @ 为参数的 HTML 特性添加前缀。

        正确(Title 是字符串参数, Count 是数字类型的参数):

        <ParameterChild Title="@title" Count="@ct" />
        
        <ParameterChild Title="@title" Count="ct" />
        
        <ParameterChild @Title="@title" @Count="@ct" />
        
        <ParameterChild @Title="@title" @Count="ct" />
        

        与 Razor 页面 (.cshtml) 不同,在呈现组件时,Blazor 不能在 Razor 表达式中执行异步工作。 这是因为 Blazor 是为呈现交互式 UI 而设计的。 在交互式 UI 中,屏幕必须始终显示某些内容,因此阻止呈现流是没有意义的。 相反,异步工作是在一个异步生命周期事件期间执行的。 在每个异步生命周期事件之后,组件可能会再次呈现。 不支持以下 Razor 语法:

        <ParameterChild Title="@await ..." />
        

        生成应用时,前面示例中的代码会生成编译器错误

        “await”运算符只能用于异步方法中。 请考虑用“async”修饰符标记此方法,并将其返回类型更改为“Task”。

        若要在前面的示例中异步获取 Title 参数的值,组件可以使用 OnInitializedAsync 生命周期事件,如以下示例所示:

        <ParameterChild Title="@title" />
        @code {
            private string? title;
            protected override async Task OnInitializedAsync()
                title = await ...;
        

        有关详细信息,请参阅 ASP.NET Core Razor 组件生命周期

        不支持使用显式 Razor 表达式连接文本和表达式结果以赋值给参数。 下面的示例尝试将文本“Set by ”与对象属性值连接在一起。 尽管 Razor 页面 (.cshtml) 支持此语法,但对在组件中赋值给子级的 Title 参数无效。 不支持以下 Razor 语法:

        <ParameterChild Title="Set by @(panelData.Title)" />
        

        生成应用时,前面示例中的代码会生成编译器错误

        组件属性不支持复杂内容(混合 C# 和标记)。

        若要支持组合值赋值,请使用方法、字段或属性。 下面的示例在 C# 方法 GetTitle 中将“Set by ”与对象属性值连接在一起:

        ParameterParent3.razor

        @page "/parameter-parent-3" <ParameterChild Title="@GetTitle()" /> @code { private PanelData panelData = new(); private string GetTitle() => $"Set by {panelData.Title}"; private class PanelData public string Title { get; set; } = "Parent"; private PanelData panelData = new(); private string GetTitle() => $"Set by {panelData.Title}"; private class PanelData public string Title { get; set; } = "Parent"; private PanelData panelData = new(); private string GetTitle() => $"Set by {panelData.Title}"; private class PanelData public string Title { get; set; } = "Parent"; 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 中的参数

        应将组件参数声明为自动属性,这意味着它们不应在其 getset 访问器中包含自定义逻辑。 例如,下面的 StartData 属性是自动属性:

        [Parameter]
        public DateTime StartData { get; set; }
        

        不要在 getset 访问器中放置自定义逻辑,因为组件参数专门用作父组件向子组件传送信息的通道。 如果子组件属性的 set 访问器包含导致父组件重新呈现的逻辑,则会导致一个无限的呈现循环。

        若要转换已接收的参数值,请执行以下操作:

      • 将参数属性保留为自动属性,以表示所提供的原始数据。
      • 创建另一个属性或方法,用于基于参数属性提供转换后的数据。
      • 替代 OnParametersSetAsync 以在每次收到新数据时转换接收到的参数。

        支持将初始值写入组件参数,因为初始值赋值不会干扰 Blazor 的自动组件呈现。 在组件中,使用 DateTime.Now 将当前本地 DateTime 赋予 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 访问器。 组件通常使用反射实例化和分配参数值,从而绕过了 initrequired 本应做出的保证。 请改为使用 [EditorRequired] 特性以指定所需的组件参数。

        不要对组件参数属性使用 init 访问器,因为设置具有 ParameterView.SetParameterProperties 的组件参数值会使用反射,这会绕过仅初始化的资源库限制。 应用 [EditorRequired] 特性以指定所需的组件参数。

        不要对组件参数属性使用 init 访问器,因为设置具有 ParameterView.SetParameterProperties 的组件参数值会使用反射,这会绕过仅初始化的资源库限制。

        组件参数和 RenderFragment 类型支持 TuplesAPI 文档)。 下面的组件参数示例在 Tuple 中传递三个值:

        RenderTupleChild.razor

        <div class="card w-50" style="margin-bottom:15px"> <div class="card-header font-weight-bold"><code>Tuple</code> Card</div> <div class="card-body"> <li>Integer: @Data?.Item1</li> <li>String: @Data?.Item2</li> <li>Boolean: @Data?.Item3</li> @code { [Parameter] public (int, string, bool)? Data { get; set; }

        RenderTupleParent.razor

        @page "/render-tuple-parent" <h1>Render Tuple Parent</h1> <RenderTupleChild Data="@data" /> @code { private (int, string, bool) data = new(999, "I aim to misbehave.", true);

        支持命名元组,如以下示例所示:

        RenderNamedTupleChild.razor

        <div class="card w-50" style="margin-bottom:15px"> <div class="card-header font-weight-bold"><code>Tuple</code> Card</div> <div class="card-body"> <li>Integer: @Data?.TheInteger</li> <li>String: @Data?.TheString</li> <li>Boolean: @Data?.TheBoolean</li> @code { [Parameter] public (int TheInteger, string TheString, bool TheBoolean)? Data { get; set; }

        RenderNamedTupleParent.razor

        @page "/render-named-tuple-parent" <h1>Render Named Tuple Parent</h1> <RenderNamedTupleChild Data="@data" /> @code { private (int TheInteger, string TheString, bool TheBoolean) data = new(999, "I aim to misbehave.", true);

        引用 ©2005 环球影业冲出宁静号内森·菲利安

        组件可以在 @page 指令的路由模板中指定路由参数。 Blazor 路由器使用路由参数来填充相应的组件参数。

        支持可选路由参数。 在下面的示例中,text 可选参数将 route 段的值赋给组件的 Text 属性。 如果该段不存在,则在 OnInitialized 生命周期方法中将 Text 的值设置为 fantastic

        不支持可选路由参数,因此在下面的示例中应用了两个 @page 指令。 第一个 @page 指令允许导航到没有路由参数的组件。 第二个 @page 指令接收 {text} 路由参数,并将值分配给 Text 属性。

        RouteParameter.razor

        @page "/route-parameter/{text?}" <h1>Blazor is @Text!</h1> @code { [Parameter] public string? Text { get; set; } protected override void OnInitialized() Text = Text ?? "fantastic";

        有关捕获跨越多个文件夹边界的路径的 catch-all 路由参数 ({*pageRoute}) 的信息,请参阅 ASP.NET Core Blazor 路由和导航

        子内容呈现片段

        组件可以设置另一个组件的内容。 分配组件提供子组件的开始标记与结束标记之间的内容。

        在下面的示例中,RenderFragmentChild 组件具有一个 ChildContent 组件参数,它将要呈现的 UI 段表示为 RenderFragmentChildContent 在组件 Razor 标记中的位置是在最终 HTML 输出中呈现内容的位置。

        RenderFragmentChild.razor

        <div class="card w-25" style="margin-bottom:15px"> <div class="card-header font-weight-bold">Child content</div> <div class="card-body">@ChildContent</div> @code { [Parameter] public RenderFragment? ChildContent { get; set; } <div class="card w-25" style="margin-bottom:15px"> <div class="card-header font-weight-bold">Child content</div> <div class="card-body">@ChildContent</div> @code { [Parameter] public RenderFragment? ChildContent { get; set; } <div class="card w-25" style="margin-bottom:15px"> <div class="card-header font-weight-bold">Child content</div> <div class="card-body">@ChildContent</div> @code { [Parameter] public RenderFragment ChildContent { get; set; } <div class="card w-25" style="margin-bottom:15px"> <div class="card-header font-weight-bold">Child content</div> <div class="card-body">@ChildContent</div> @code { [Parameter] public RenderFragment ChildContent { get; set; }

        必须按约定将接收 RenderFragment 内容的属性命名为 ChildContent

        RenderFragment 不支持事件回叫

        以下 RenderFragmentParent 组件通过将内容置于子组件的开始标记和结束标记内,来提供用于呈现 RenderFragmentChild 的内容。

        RenderFragmentParent.razor

        @page "/render-fragment-parent" <h1>Render child content</h1> <RenderFragmentChild> Content of the child component is supplied by the parent component. </RenderFragmentChild>

        由于 Blazor 呈现子内容的方式,如果在 RenderFragmentChild 组件的内容中使用递增循环变量,则在 for 循环内呈现组件需要本地索引变量。 下面的示例可以添加到前面的 RenderFragmentParent 组件:

        <h1>Three children with an index variable</h1>
        @for (int c = 0; c < 3; c++)
            var current = c;
            <RenderFragmentChild>
                Count: @current
            </RenderFragmentChild>
        

        或者,将 foreach 循环与 Enumerable.Range 结合使用,而不是使用 for 循环。 下面的示例可以添加到前面的 RenderFragmentParent 组件:

        <h1>Second example of three children with an index variable</h1>
        @foreach (var c in Enumerable.Range(0,3))
            <RenderFragmentChild>
                Count: @c
            </RenderFragmentChild>
        

        呈现片段用于在整个 Blazor 应用中呈现子内容,在下面的文章和文章部分中有示例介绍:

      • Blazor 布局
      • 跨组件层次结构传递数据
      • 模板化组件
      • 全局异常处理
      • Blazor 框架的内置 Razor 组件使用相同的 ChildContent 组件参数约定来设置其内容。 可以通过在 API 文档(使用搜索词“ChildContent”筛选 API)中搜索组件参数属性名称 ChildContent 来查看设置子内容的组件。

        可重用呈现逻辑的呈现片段

        你可以分解出子组件,纯粹作为重复使用呈现逻辑的方法。 在任何组件的 @code 块中,根据需要定义 RenderFragment 并呈现任意位置的片段:

        @RenderWelcomeInfo
        <p>Render the welcome info a second time:</p>
        @RenderWelcomeInfo
        @code {
            private RenderFragment RenderWelcomeInfo =  @<p>Welcome to your new app!</p>;
        

        有关详细信息,请参阅重复使用呈现逻辑

        捕获对组件的引用

        组件引用提供了一种引用组件实例以便发出命令的方法。 若要捕获组件引用,请执行以下操作:

      • 向子组件添加 @ref 特性。
      • 定义与子组件类型相同的字段。
      • 呈现组件时,将用组件实例填充字段。 然后,可以在实例上调用 .NET 方法。

        请考虑以下 ReferenceChild 组件,它会在调用其 ChildMethod 时记录消息。

        ReferenceChild.razor

        @using Microsoft.Extensions.Logging @inject ILogger<ReferenceChild> Logger @code { public void ChildMethod(int value) Logger.LogInformation("Received {Value} in ChildMethod", value); public void ChildMethod(int value) Logger.LogInformation("Received {Value} in ChildMethod", value); public void ChildMethod(int value) Logger.LogInformation("Received {Value} in ChildMethod", value); public void ChildMethod(int value) Logger.LogInformation("Received {Value} in ChildMethod", value);

        组件引用仅在呈现组件后才进行填充,其输出包含 ReferenceChild 的元素。 在呈现组件之前,没有任何可引用的内容。

        若要在组件完成呈现后操作组件引用,请使用 OnAfterRenderOnAfterRenderAsync 方法

        若要结合使用事件处理程序和引用变量,请使用 Lambda 表达式,或在 OnAfterRenderOnAfterRenderAsync 方法中分配事件处理程序委托。 这可确保在分配事件处理程序之前先分配引用变量。

        以下 lambda 方法使用前面的 ReferenceChild 组件。

        ReferenceParent1.razor

        @page "/reference-parent-1" <button @onclick="@(() => childComponent?.ChildMethod(5))"> Call <code>ReferenceChild.ChildMethod</code> with an argument of 5 </button> <ReferenceChild @ref="childComponent" /> @code { private ReferenceChild? childComponent; <button @onclick="@(() => childComponent?.ChildMethod(5))"> Call <code>ReferenceChild.ChildMethod</code> with an argument of 5 </button> <ReferenceChild @ref="childComponent" /> @code { private ReferenceChild? childComponent; <button @onclick="@(() => childComponent.ChildMethod(5))"> Call <code>ReferenceChild.ChildMethod</code> with an argument of 5 </button> <ReferenceChild @ref="childComponent" /> @code { private ReferenceChild childComponent; <button @onclick="@(() => childComponent.ChildMethod(5))"> Call <code>ReferenceChild.ChildMethod</code> with an argument of 5 </button> <ReferenceChild @ref="childComponent" /> @code { private ReferenceChild childComponent;

        以下委托方法使用前面的 ReferenceChild 组件。

        ReferenceParent2.razor

        @page "/reference-parent-2" <button @onclick="@(() => callChildMethod?.Invoke())"> Call <code>ReferenceChild.ChildMethod</code> with an argument of 5 </button> <ReferenceChild @ref="childComponent" /> @code { private ReferenceChild? childComponent; private Action? callChildMethod; protected override void OnAfterRender(bool firstRender) if (firstRender) callChildMethod = CallChildMethod; private void CallChildMethod() childComponent?.ChildMethod(5); <button @onclick="@(() => callChildMethod?.Invoke())"> Call <code>ReferenceChild.ChildMethod</code> with an argument of 5 </button> <ReferenceChild @ref="childComponent" /> @code { private ReferenceChild? childComponent; private Action? callChildMethod; protected override void OnAfterRender(bool firstRender) if (firstRender) callChildMethod = CallChildMethod; private void CallChildMethod() childComponent?.ChildMethod(5); <button @onclick="callChildMethod"> Call <code>ReferenceChild.ChildMethod</code> with an argument of 5 </button> <ReferenceChild @ref="childComponent" /> @code { private ReferenceChild childComponent; private Action callChildMethod; protected override void OnAfterRender(bool firstRender) if (firstRender) callChildMethod = CallChildMethod; private void CallChildMethod() childComponent.ChildMethod(5); <button @onclick="callChildMethod"> Call <code>ReferenceChild.ChildMethod</code> with an argument of 5 </button> <ReferenceChild @ref="childComponent" /> @code { private ReferenceChild childComponent; private Action callChildMethod; protected override void OnAfterRender(bool firstRender) if (firstRender) callChildMethod = CallChildMethod; private void CallChildMethod() childComponent.ChildMethod(5);

        尽管捕获组件引用使用与捕获元素引用类似的语法,但捕获组件引用不是 JavaScript 互操作功能。 组件引用不会传递给 JavaScript 代码。 组件引用只在 .NET 代码中使用。

        不要使用组件引用来改变子组件的状态。 请改用常规声明性组件参数将数据传递给子组件。 使用组件参数使子组件在正确的时间自动重新呈现。 有关详细信息,请参阅组件参数部分和 ASP.NET Core Blazor 数据绑定一文。

        可以通过 @attribute 指令将特性应用于组件。 下面的示例将 [Authorize] 特性应用于组件的类:

        @page "/"
        @attribute [Authorize]
        

        条件 HTML 元素属性

        HTML 元素特性属性基于 .NET 值有条件地设置。 如果值为 falsenull,则属性未设置。 如果值为 true,则属性已设置。

        在下面的示例中,IsCompleted 确定是否设置了 <input> 元素的 checked 属性。

        ConditionalAttribute.razor

        @page "/conditional-attribute" <label> <input type="checkbox" checked="@IsCompleted" /> Is Completed? </label> <button @onclick="@(() => IsCompleted = !IsCompleted)"> Change IsCompleted </button> @code { [Parameter] public bool IsCompleted { get; set; }

        当 .NET 类型为 bool 时,某些 HTML 特性(如 aria-pressed)无法正常运行。 在这些情况下,请使用 string 类型,而不是 bool

        原始 HTML

        通常使用 DOM 文本节点呈现字符串,这意味着将忽略它们可能包含的任何标记,并将其视为文字文本。 若要呈现原始 HTML,请将 HTML 内容包装在 MarkupString 值中。 将该值分析为 HTML 或 SVG,并插入到 DOM 中。

        呈现从任何不受信任的源构造的原始 HTML 存在安全风险,应始终避免

        下面的示例演示如何使用 MarkupString 类型向组件的呈现输出添加静态 HTML 内容块。

        MarkupStringExample.razor

        @page "/markup-string-example" @((MarkupString)myMarkup) @code { private string myMarkup = "<p class=\"text-danger\">This is a dangerous <em>markup string</em>.</p>"; @code { private string myMarkup = "<p class=\"text-danger\">This is a dangerous <em>markup string</em>.</p>"; @code { private string myMarkup = "<p class=\"text-danger\">This is a dangerous <em>markup string</em>.</p>"; @code { private string myMarkup = "<p class=\"text-danger\">This is a dangerous <em>markup string</em>.</p>";

        Razor 模板

        可以使用 Razor 模板语法定义呈现片段,从而定义 UI 片段。 Razor 模板使用以下格式:

        @<{HTML tag}>...</{HTML tag}>
        

        下面的示例演示如何在组件中指定 RenderFragmentRenderFragment<TValue> 值并直接呈现模板。 还可以将呈现片段作为参数传递给模板化组件

        RazorTemplate.razor

        @page "/razor-template" @timeTemplate @petTemplate(new Pet { Name = "Nutty Rex" }) @code { private RenderFragment timeTemplate = @<p>The time is @DateTime.Now.</p>; private RenderFragment<Pet> petTemplate = (pet) => @<p>Pet: @pet.Name</p>; private class Pet public string? Name { get; set; } @code { private RenderFragment timeTemplate = @<p>The time is @DateTime.Now.</p>; private RenderFragment<Pet> petTemplate = (pet) => @<p>Pet: @pet.Name</p>; private class Pet public string? Name { get; set; } @code { private RenderFragment timeTemplate = @<p>The time is @DateTime.Now.</p>; private RenderFragment<Pet> petTemplate = (pet) => @<p>Pet: @pet.Name</p>; private class Pet public string Name { get; set; } @code { private RenderFragment timeTemplate = @<p>The time is @DateTime.Now.</p>; private RenderFragment<Pet> petTemplate = (pet) => @<p>Pet: @pet.Name</p>; private class Pet public string Name { get; set; }

        以上代码的呈现输出:

        <p>The time is 4/19/2021 8:54:46 AM.</p>
        <p>Pet: Nutty Rex</p>
        

        Blazor 遵循 ASP.NET Core 应用对于静态资产的约定。 静态资产位于项目的 web root (wwwroot) 文件夹中或是 wwwroot 文件夹下的文件夹中。

        使用基相对路径 (/) 来引用静态资产的 Web 根。 在下面的示例中,logo.png 实际位于 {PROJECT ROOT}/wwwroot/images 文件夹中。 {PROJECT ROOT} 是应用的项目根。

        <img alt="Company logo" src="/images/logo.png" />
        

        组件不支持波浪符斜杠表示法 (~/)。

        有关设置应用基本路径的信息,请参阅托管和部署 ASP.NET Core Blazor

        组件中不支持标记帮助程序

        组件中不支持 Tag Helpers。 若要在 Blazor 中提供类似标记帮助程序的功能,请创建一个具有与标记帮助程序相同功能的组件,并改为使用该组件。

        可缩放的向量图形 (SVG) 图像

        由于 Blazor 呈现 HTML,因此通过 <img> 标记支持浏览器支持的图像,包括可缩放的矢量图形 (SVG) 图像 (.svg)

        <img alt="Example image" src="image.svg" />
        

        同样,样式表文件 (.css) 的 CSS 规则支持 SVG 图像:

        .element-class {
            background-image: url("image.svg");
        

        Blazor 支持 <foreignObject> 元素在 SVG 中显示任意 HTML。 标记可表示任意 HTML、RenderFragment 或 Razor 组件。

        下面的示例展示了如何:

      • string (@message) 的显示情况。
      • 具有 <input> 元素和 value 字段的双向绑定。
      • Robot 组件。
      • <svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
            <rect x="0" y="0" rx="10" ry="10" width="200" height="200" stroke="black" 
                fill="none" />
            <foreignObject x="20" y="20" width="160" height="160">
                <p>@message</p>
            </foreignObject>
        <svg xmlns="http://www.w3.org/2000/svg">
            <foreignObject width="200" height="200">
                <label>
                    Two-way binding:
                    <input @bind="value" @bind:event="oninput" />
                </label>
            </foreignObject>
        <svg xmlns="http://www.w3.org/2000/svg">
            <foreignObject>
                <Robot />
            </foreignObject>
        @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<TValue> 参数中的前导或尾随(例如,传递到另一个组件的子内容)。
      • 在 C# 代码块(例如 @if@foreach)之前或之后。
      • 但是,在使用 CSS 规则(例如 white-space: pre)时,删除空白可能会影响呈现输出。 若要禁用此性能优化并保留空白,请执行以下任一操作:

      • @preservewhitespace true 指令添加到 Razor 文件 (.razor) 的顶部,从而将首选项应用于特定组件。
      • @preservewhitespace true 指令添加到 _Imports.razor 文件中,从而将首选项应用于子目录或整个项目。
      • 在大多数情况下,不需要执行任何操作,因为应用程序通常会继续正常运行(但速度会更快)。 如果去除空白会导致特定组件出现呈现问题,请在该组件中使用 @preservewhitespace true 来禁用此优化。

        空白将保留在组件的源标记中。 即使在没有视觉效果的情况下,只有空白的文本也会呈现在浏览器的 DOM 中。

        请考虑以下组件标记:

        @foreach (var item in Items) @item.Text

        前面的示例呈现以下不必要的空白:

      • @foreach 代码块外。
      • 围绕 <li> 元素。
      • 围绕 @item.Text 输出。
      • 100 项的列表会导致超过 400 个空白区域。 任何额外空白都不会在视觉上影响呈现的输出。

        呈现组件的静态 HTML 时,不会保留标记中的空白。 例如,查看组件 Razor 文件 (.razor) 中以下 <img> 标记的呈现输出:

        <img     alt="Example image"   src="img.png"     />
        

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

        <img alt="Example image" src="img.png" />
        

        呈现静态根 Razor 组件

        根 Razor 组件是加载应用创建的任何组件层次结构的第一个组件。

        在从 Blazor Web App 项目模板创建的应用中,App 组件 (App.razor) 由向服务器侧 Program 文件调用 MapRazorComponents<TRootComponent> 声明的类型参数指定为默认根组件。 以下示例演示如何使用 App 组件作为根组件,这是从 Blazor 项目模板创建的应用的默认组件:

        app.MapRazorComponents<App>();
        

        在从 Blazor Server 项目模板创建的应用中,使用 组件标记帮助程序App 组件 (App.razor) 指定为 Pages/_Host.cshtml 中的默认根组件:

        <component type="typeof(App)" render-mode="ServerPrerendered" />
        

        在从 Blazor WebAssembly 项目模板创建的应用中,将 App 组件 (App.razor) 指定为 Program 文件中的默认根组件:

        builder.RootComponents.Add<App>("#app");
        

        在前面的代码中,CSS 选择器 #app 指示为 wwwroot/index.html 中的 <div> 指定了 App 组件,其中 idapp

        <div id="app">...</app>
        

        MVC 和 Razor Pages 应用还可以使用组件标记帮助程序来注册静态呈现的 Blazor WebAssembly 根组件:

        <component type="typeof(App)" render-mode="WebAssemblyPrerendered" />
        

        静态呈现的组件只能添加到应用。 之后无法移除或更新它们。

        有关更多信息,请参见以下资源:

      • ASP.NET Core 中的组件标记帮助程序
      • 预呈现和集成 ASP.NET Core Razor 组件
  •