第三章 组件(1)- 概述

注意,从这里开始,往后的文章中,Blazor项目指的都是Blazor Web App下的Server模式。

组件的基类

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

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

  • 可以看出,实际上组件就是一个C#类。

开发人员可以通过 Razor 组件文件 (.razor) 来构建 Razor 组件或者通过创建C#类型并继承ComponentBase来构建组件。此外,也可以通过实现IComponent来生成组件,从而对组件更加高度自定义的控制,但是实现IComponent就需要开发人员使用事件和生命周期方法手动触发渲染,且这些事件和方法必须由开发人员创建和维护。

Razor 语法

组件中可以使用 Razor 语法,其中会较为频繁使用了两个 Razor 功能,即指令和属性指令。

指令

Razoe指定用于更改组件标记的分析或运行方式。 例如,[@page](https://learn.microsoft.com/zh-cn/aspnet/core/mvc/views/razor?view=aspnetcore-8.0#page) 指令使用路由模板指定可路由组件,可以由用户请求在浏览器中按特定 URL 直接访问。
官方给了在组件中使用各种指令时的排放顺序规范,但并不是必须这么去排序的,具体如下:

  • @page
  • @rendermode(.NET 8 或更高版本)
  • @using
    • System 命名空间(字母顺序)
    • Microsoft 命名空间(字母顺序)
    • 第三方 API 命名空间(字母顺序)
    • 应用命名空间(字母顺序)
  • 其他指令(字母顺序)

然后,指令和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<DoctorWhoEpisodes> Logger
    
    <PageTitle>Doctor Who Episode List</PageTitle>
    
    ...
    

属性指令

属性指令一般也是用于更改嘴贱元素的分析方式或运行方式的。

  • 示例

    <input @bind="episodeId" />
    

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

命名规则

  • 组件的名称必须以大写字符开头。
  • 文件路径和文件名建议使用Pascal大小写,例如Components/Pages/ProductDetail.razor
  • 可路由组件的URL路径,建议使用kebab大小写,例如"/product-detail"

命名空间规则

  • 可路由的组件通常位于 Components/Pages 文件夹中。
  • 非可路由组件(也就是没有用@page指令的组件)通常放置在 Components 文件夹或添加到项目的自定义文件夹中。
  • 组件的命名空间是从应用的根命名空间和该组件在项目内的位置(文件夹)派生而来的。 例如应用的根命名空间是 BlazorSample,并且 Counter 组件位于 Components/Pages 文件夹中:Counter 组件的命名空间为 BlazorSample.Components.Pages。组件的完全限定类型名称为 BlazorSample.Components.Pages.Counter
  • 可以使用完全限定名来引用组件,这时不需要@using命令导入命名空间,例如:<BlazorSample.Components.Pages.Counter/>
  • 对于保存组件的自定义文件夹,最好使用 @using 指令添加到父组件或项目的 _Imports.razor 文件全局引用。需要注意的是,_Imports.razor 文件中的 @using 指令仅适用于 Razor 文件 (.razor),而不适用于 C# 文件 (.cs)。
  • 不支持global::
  • 不支持使用@using只引入部分命名空间,然后补全引用组件。例如,组件Components/Layout/NavMenu.razor,不能在要使用NavMenu组件的组件上,通过@using BlazorSample.Components引入部分命名空间,然后通过<Layout.NavMenu></Layout.NavMenu>来引用组件。
  • 不支持@using的别名指定,例如不支持@using AAA=BlazorApp7.Components.Layout

支持分部类

Blazor项目中的组件,本质就是继承了ComponentBase的C#类,既然是C#类,那么就支持分部类。

一般情况下,为了方便,Razor标签、HTML和@code块都放在同一个.razor文件中,例如Blazor项目模板中生成的Counter.razor组件。但当我们组件中相关业务逻辑较多较复杂时,全部都写在一个.razor文件中不免显得有些臃肿,这个时候就可以通过分部类,将C#相关的代码放置到部分类中。

组件的分部类的文件名建议名为xxxx.razor.cs,类似css隔离的用法。以项目模板中的Counter.razor组件为例子,将其中的计数方法和属性剥离到分部类中:

在这里插入图片描述

  • Counter.razor

    @page "/counter"
    @rendermode InteractiveServer
    
    <PageTitle>Counter</PageTitle>
    
    <h1>Counter</h1>
    
    <p role="status">Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
  • Counter.razor.cs

    using Microsoft.AspNetCore.Components;
    
    namespace BlazorServer.Components.Pages
    {
        public partial class Counter
        {
            private int currentCount = 0;
            private void IncrementCount()
            {
                currentCount++;
            }
        }
    }
    
    

指定基类

@inherits指令用于指定组件的基类。 与使用分部类不同,分部类仅在 C# 逻辑上拆分组件,而使用基类可以继承 C# 代码,以便在具有共同特征的组件之间共用基类的属性和方法。

  • BlazorRocks.razor

    @page "/blazor-rocks-"
    @inherits BlazorRocksBase
    
    <PageTitle>Blazor Rocks!</PageTitle>
    
    <h1>Blazor Rocks! Example 1</h1>
    
    <p>
        @BlazorRocksText
    </p>
    
  • BlazorRocksBase.cs

    using Microsoft.AspNetCore.Components;
    
    namespace BlazorSample;
    
    public class BlazorRocksBase : ComponentBase
    {
        public string BlazorRocksText { get; set; } =
            "Blazor rocks the browser!";
    }
    

async方法不支持返回void

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

组件实例的引用

Blazor提供了一种引用组件实例的方法,为的是方便在使用组件时,父组件可以通过组件实例调用对应的方法,从而更加灵活的使用组件。

使用方式

  • 定义与目标组件类型相同的字段。
  • 使用目标组件时,以内联的方式,使用@ref属性指令设置对应的字段名称。

注意

组件引用仅在渲染组件后才开始赋值。在组件渲染完成之前,没有任何可以引用的内容,因此如果要调用组件引用中的方法时,要考虑正确的调用时机。

  • 不要直接在组件的事件中调用组件引用的方法,因为在分配单击事件时可能不会分配引用变量,例如<MyComponent @onclick="childComponent!.ChildMethod(5)"/>
  • 若要在组件完成渲染后操作组件引用,可以使用OnAfterRenderOnAfterRenderAsync方法。

示例

  • ReferenceChild.razor

    @inject ILogger<ReferenceChild> Logger
    
    @if (value > 0)
    {
        <p>
            <code>value</code>: @value
        </p>
    }
    
    @code {
        private int value;
    
        public void ChildMethod(int value)
        {
            Logger.LogInformation("Received {Value} in ChildMethod", value);
    
            this.value = value;
            StateHasChanged();
        }
    }
    
  • ReferenceParent.razor

    @page "/reference-parent"
    
    <div>
        <button @onclick="@(() => childComponent1!.ChildMethod(5))">
            Call <code>ReferenceChild.ChildMethod</code> (first instance) 
            with an argument of 5
        </button>
    
        <ReferenceChild @ref="childComponent1"/>
    </div>
    
    <div>
        <button @onclick="CallChildMethod">
            Call <code>ReferenceChild.ChildMethod</code> (second instance) 
            with an argument of 5
        </button>
    
        <ReferenceChild @ref="childComponent2"/>
    </div>
    
    @code {
        private ReferenceChild? childComponent1;
        private ReferenceChild? childComponent2;
    
        private void CallChildMethod()
        {
            childComponent2!.ChildMethod(5);
        }
    }
    

相关推荐

  1. 1 计算机系统概述(2)

    2024-04-20 23:56:01       29 阅读
  2. :Three.js 基本概念

    2024-04-20 23:56:01       11 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-20 23:56:01       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-20 23:56:01       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-20 23:56:01       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-20 23:56:01       18 阅读

热门阅读

  1. C. Vasilije in Cacak

    2024-04-20 23:56:01       12 阅读
  2. 动态规划(Dynamic Programming,简称 DP)

    2024-04-20 23:56:01       11 阅读
  3. python应用笔记之ctypes加快crc32计算

    2024-04-20 23:56:01       13 阅读
  4. python中isinstance()作用

    2024-04-20 23:56:01       16 阅读
  5. nodejs npm 常用的命令

    2024-04-20 23:56:01       16 阅读
  6. 每日算法4.17

    2024-04-20 23:56:01       15 阅读
  7. K8s: 在Pod里面对容器进行配额管理和相关原理

    2024-04-20 23:56:01       17 阅读
  8. 牛客网华为机试题说明三

    2024-04-20 23:56:01       15 阅读
  9. RDP连接Ubuntu远程桌面

    2024-04-20 23:56:01       16 阅读
  10. ZCMU 1510: Love Letter

    2024-04-20 23:56:01       49 阅读