ASP.NET Core中的Blazor组件介绍

目录
  • 关于组件
  • 组件类
  • 静态资产
  • 路由与路由参数
  • 组件参数
  • 请勿创建会写入其自己的组参数属性的组件
  • 子内容
  • 属性展开
  • 任意参数
  • 捕获对组件的引用
  • 在外部调用组件方法以更新状态
  • 使用 @ 键控制是否保留元素和组件
  • 指定基类
  • 指定属性
  • 导入组件
  • 原始 HTML

项目 Blazor 中,使用 .razor 结尾的文件,称为组件;而 Blazor 中的组件,正式名称是 razor 组件;

Blazor 组件是 razor 过渡而来的,使用 razor 的基本语法特性,但是 Balzor 不支持 razor 中的标记帮助程序。

关于组件

.razor 文件分为页面(带@page)和组件(不带@page,或者说页面组件和非页面组件。两者区别在于页面有路由,可以直接通过 URI 访问,一般放在 Page 文件夹中;而组件,作为一个部件,必须嵌入其它组件中,在页面中显示,一般放到 Shared 文件夹中,供多个页面共享、复用。
本文接下来所指的组件都是非页面组件。
.razor 文件中,开头有 @page 标记的,就是页面组件,没有的就是非页面组件。
当然两者并没有严格的区分。
组件命名时,应该带上 Component 后缀。

组件类

每个 .razor 文件,在编译后会生成一个类,称为组件类。 生成的类的名称与文件名匹配。
因此,每个 .razor 文件,必须以大写字母开头,按照类名命名规范定义文件名称。

`.razor` ,以 `@code{}` 包含 C# 代码,这部分代码除了组件间可以使用,程序中也可以正常使用,因为属于类的一部分。

创建 Test.razor 文件,文件内容如下:

@code{
    public string Name { get; set; }
}

Pargrom 中:

            Pages.Test test = new Pages.Test();
            test.Name = "Blazor";

简单来说,就是可以作为一个类来使用。@code{} 中定义的成员,就是类的成员。
成员正常使用 public 、private 等访问修饰符修饰。

静态资产

默认静态资源文件位置在项目的 wwwroot 目录,前端(.razor、.cshtml)等,默认寻址时,使用绝对路径 / 即可访问资源。
例如:

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

这个路径是要放到前端才能,由前端访问时 ASP.NET Core 框架自动处理,相当于前端访问 / ,后端访问 D:/test/Blazor/wwwroot

路由与路由参数

页面组件使用 @page 设置此页面的访问地址,这里没有 Controller 和 Action 的分层和路由导航(相对地址),直接是一个绝对的访问地址,并且全局唯一。

Index.razor 中,路由:

@page "/"

Blazor 不支持像 Controller 和 Action 那样设置灵活的 URL 可选参数(URL Query),例如:

        [HttpGet("Test/{Id}")]
        public string Test([FromQuery]int Id)
        {
            return "123";
        }

Blazor 如果想通过 URL Query 传递参数,可以使用 {Name}

@page "/test"
@page "/test/{Id}"

<h2>@Id</h2>

@code{
    [Parameter]
    public string Id { get; set; } = "123";
}

因为 Blazor 不支持可选参数,因此,如果只设置 @page "/test/{Id}",那么每次访问都必须带有这个参数值。
需要使用 [Parameter] 来修饰成员,才能捕获 @page "/test/{Id}"
另外,理由参数是 string 类型,不能自动转为数值类型。不如会报错:

InvalidOperationException: Unable to set property 'Id' on object of type 'BlazorApp1.Pages.Test'. The error was: Unable to cast object of type 'System.String' to type 'System.Int32'.

你可以接收后,显式转为数值类型。

组件参数

在 @code 代码块中,使用 [Parameter] 修饰的公共属性,那么这个属性就会标识为组件指定参数。
注意官网文档中,这个小节的代码示例,实际是不允许这样写得的。
目前,有两个地方需要使用 [Parameter] 特性,一个是前一小节的路由参数绑定,另一个是嵌入组件时使用。
示例:
Test.razor 文件内容:

<h2>@Title</h2>

@code{
    [Parameter]
    public string Title { get; set; } = "test";
}

别的组件嵌入 Test.razor 这个组件时,就可以使用 Title 传递参数进去:

<Test Title="111" />

请勿创建会写入其自己的组参数属性的组件

前面我们说到, [Parameter] 特性的使用,这个特性时作为参数传递而使用的。
对于路由参数,其修饰的属性应该是 privite,对于其它组件传递参数,属性应该设置为 public
如果一个组件的 @code{} 成员不需要被外界作为参数使用,就应该设置为 private
因为 .razor 一般不会作为类来使用。、;而且不设置 [Parameter] 的属性,别的组件也使用不了这个属性。

那么,文档说 “请勿创建会写入其自己的组参数属性的组件”,指定是 [Parmeter] 休息的属性,是作为参数传递使用的,不要在组件中修改这个属性的值。

如果实在要操作的话,可以先拷贝这个值,使用别的变量操作,示例:

<h2>@Title</h2>

@code{
    [Parameter]
    public string Title { get; set; } = "test";

    private string _Title;
    protected override void OnInitialized()
    {
        _Title = Title;
    }
}

这样,组件要操作的话,可以使用 _Title ,保留 Title
OnInitalized() 是一个组件初始化的方法,也可以理解成构造函数,可以参考 https://docs.microsoft.com/zh-cn/aspnet/core/blazor/lifecycle?view=aspnetcore-3.1#component-initialization-methods

子内容

因为组件是可以嵌套的,可以要求另一个组件显示要求的内容。

  • 被多个组件使用,不同组件要呈现不一样的内容;
  • 要根据父组件的配置,显示子组件;
  • 组件 A 要求使用到的组件 B,显示其传递的内容;

简单来说,就是将页面内容作为复杂类型传递给另一个组件,要求这个组件显示出来。
那么,子内容指的是一个组件可以接收另一个组件的内容,使用 RenderFragment 来接收内容。
示例如下:
Test.razor 中,内容:

<div>@Children</div>

@code{
    [Parameter]
    public RenderFragment Children { get; set; }
}

另一个组件:

@page "/"

<Test Children=r />
@code{
    private RenderFragment r =@<h1>测试子内容</h1>;
}

RenderFragment 的使用,请自行查阅资料。

属性展开

属性展开是使用字典类型表示一个 Html 标签的多个属性。

<input id="1"
       maxlength="@Maxlength"
       placeholder="@Placeholder"
       required="@Required"
       size="@Size" />

<input id="2"
       @attributes="InputAttributes" />

@code {
    #region
    private string Maxlength { get; set; } = "10";
    private string Placeholder { get; set; } = "Input placeholder text";
    private string Required { get; set; } = "required";
    private string Size { get; set; } = "50";
    #endregion

    // 使用字典键值对表示
    public Dictionary<string, object> InputAttributes { get; set; } = new Dictionary<string, object>()
    {
            { "maxlength", "10" },
            { "placeholder", "Input placeholder text" },
            { "required", "required" },
            { "size", "50" }
     };
}

任意参数

[Paramter] 特性,只有一个属性,其定义如下:

        public bool CaptureUnmatchedValues { get; set; }

文档说明:[Parameter] 上的 CaptureUnmatchedValues 属性允许参数匹配所有不匹配任何其他参数的特性。
其作用是通过字典接收在父组件中出现但是未在 @code{} 中定义的参数属性。
例如:
Test.razor 中

@code{
    // 这个属性没有用,随便起个名字测试
    [Parameter]
    public string A { get; set; }

    [Parameter(CaptureUnmatchedValues = true)]
    public IDictionary<string, object> AdditionalAttributes { get; set; }
}

父组件中使用:

<Test A="A"
      B="B"
      C="C" />

B、C 都是 Test.razor 中没有出现过的,那么这些参数和参数值都会自动转为键值对存储到 AdditionalAttributes 中。

测试示例:
Test.razor 中的内容

<ul>
    @foreach (var item in AdditionalAttributes)
    {
        <li>@item.Key - @item.Value</li>
    }
</ul>

@code{
    // 这个属性没有用,随便起个名字测试
    [Parameter]
    public string TTT { get; set; }

    [Parameter(CaptureUnmatchedValues = true)]
    public IDictionary<string, object> AdditionalAttributes { get; set; }
}

其它组件使用:

@page "/"

<Test TTT="ces"
      id="useIndividualParams"
      maxlength="10"
      placeholder="Input placeholder text"
      required="required"
      size="50" />

捕获对组件的引用

组件引用提供了一种引用组件实例的方法,使用 @ref 可以实现引用对参数的引用。
创建一个 Test.razor 文件,内容不限。
在一个组件中,引用该组件实例

@page "/"
<Test @ref="_test" />
@code{
    private Test _test;
}

在使用 Test.razor 组件的同时,保留了引用,以便在 @code{} 中使用其成员。

在外部调用组件方法以更新状态

组件继承了 ComponentBase 类型,有个 InvokeAsync 方法可用于外界更新此 UI 的状态。

示例如下:
创建 MyUIServer 类型,

    // 能够向所有正在打开的 Index.razor 页面发送通知
    public static class MyUIServer
    {
        // 向所有人发送通知
        public static async Task ToMessage(string message)
        {
            if (events != null)
            {
                await events.Invoke(message);
            }
        }
        public static void AddEvent(Func<string, Task> func)
        {
            events += func;
        }
        public static void RemoveEvent(Func<string, Task> func)
        {
            events -= func;
        }
        private static event Func<string, Task> events;
    }

在 Index.razor 中

@page "/"
@using BlazorApp1.Data
@implements IDisposable

<input @bind="_message" />
<button @onclick="Btn">发送消息</button>
<ul>
    @foreach (var item in messageList)
    {
        <li>@item</li>
    }
</ul>

@code {
    private string _message;
    private List<string> messageList = new List<string>();
    // 进入页面时
    protected override void OnInitialized()
    {
        MyUIServer.AddEvent(UIEvent);
    }

    // 退出当前页面UI后移除该事件
    public void Dispose()
    {
        MyUIServer.RemoveEvent(UIEvent);
    }

    protected async Task UIEvent(string message)
    {
        // 组件自带的方法,用于外部调用更新状态
        await InvokeAsync(() =>
        {
            messageList.Add(message);
            StateHasChanged();
        });
    }

    // 向所有正在访问 Index.razor 页面发送消息
    private async Task Btn()
    {
        await MyUIServer.ToMessage(_message);
    }

}

打开多个窗口,访问页面 https://localhost:5001/,在其中一个窗口输入内容并且点击按钮,即可将消息内容推送到其它窗口。

下面是一个修改官网示例的示例:
创建一个类型 NotifierService

    public class NotifierService
    {
        public async Task Update(string key, int value)
        {
            if (Notify != null)
            {
                await Notify.Invoke(key, value);
            }
        }

        public event Func<string, int, Task> Notify;
    }

该类型的 Notify 可以绑定多个事件;通过调用 Update() 方法,可以触发各个事件。
在 Startup 中注入服务 services.AddSingleton<NotifierService>();
Index.razor 中,内容为:

@page "/"
@using BlazorApp1.Data
@inject NotifierService Notifier
@implements IDisposable

<p>Last update: @_lastNotification.key = @_lastNotification.value</p>

@code {
    private (string key, int value) _lastNotification;

    protected override void OnInitialized()
    {
        Notifier.Notify += OnNotify;
    }

    public async Task OnNotify(string key, int value)
    {
        // 组件自带的方法,用于外部调用更新状态
        await InvokeAsync(() =>
        {
            _lastNotification = (key, value);
            StateHasChanged();
        });
    }

    // 退出当前页面UI后移除该事件
    public void Dispose()
    {
        Notifier.Notify -= OnNotify;
    }
}

Test.razor 文件中:

@page "/test"
@using BlazorApp1.Data
@inject NotifierService Notifier
Key:
<input @bind="Key" />
Value:
<input @bind="Value" />
<button @onclick="Update">更新</button>

@code{
    private string Key { get; set; }
    private int? Value { get; set; }
    private async Task Update()
    {
        await Notifier.Update(Key, Value.Value);
        Key = string.Empty;
        Value = null;
    }
}

然后启动项目,一个页面打开 https://localhost:5001/ ,另一个页面打开 https://localhost:5001/test
在 test 页面输入 Key 和 Value,点击按钮,即可通知到所有正在打开 Index.razor 的页面。

使用 @ 键控制是否保留元素和组件

在使用表格或了表等元素时,如果出现插入或删除、更新等情况,整个表格或列表,就会被重新渲染。这样会带来比较大的性能消耗。
一般使用绑定的元素,其更新是自动的,不需要人为控制。
在能保证每一项的某个元素列,都是唯一的时候,我们可以使用 @key 关键字来优化组件。
示例:

@page "/"
@using BlazorApp1.Data

Key:
<input @bind="_key" />
Value:
<input @bind="_value" />
<button @onclick="Add">添加</button>
<button @onclick="Remove">移除</button>
<ul>
    @foreach (var item in dic)
    {
        <li @key="item.Key">@item.Key - @item.Value</li>
    }
</ul>

@code {
    private int? _key;
    private int _value;
    private List<MyData> dic { get; set; } = new List<MyData>();
    private void Add()
    {
        if (_key == null)
            return;
        dic.Add(new MyData
        {
            Key = _key.Value,
            Value = _value
        });
        _key = null;
    }
    private void Remove()
    {
        if (_key == null)
            return;
        dic.Remove(dic.First(x => x.Key == _key.Value));
        _key = null;
    }
}

指定基类

@inherits 指令可用于指定组件的基类。 组件都默认继承了 ComponentBase 。
示例:
创建文件 TestBase.razor ,内容如下

@code{
    protected int Id { get; set; }
}

创建 Test.razor ,文件内容如下

@inherits TestBase
@code{
    public int Get()
    {
        return Id;
    }
}

指定属性

可以通过 @attribute 指令在 Razor 组件中指定组件的特性(属性)。 例如页面需要登录才能访问,则添加 [Authorize] 。

@page "/"
@attribute [Authorize]

导入组件

当要使用的组件与当前组件在同一个命名空间时,不需要“导入”,如果两者不在同一个命名空间,则可以使用 @using 导入此组件。

原始 HTML

使用 MarkupString 类型可以将字符串转为 HTML 元素对象。

@html

@code{
    public MarkupString html = (MarkupString)"<h1> Test </h1>";
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Blazor组件事件处理功能

    Blazor的组件当中, 提供了事件处理功能, 这点类似于使用客户端(Winform/Wpf)开发, 经常用到的一些类似: 按钮(Button), 输入框(TextBox) 用到的一些事件, 例如Click.DoubleClick.TextChanged 等等事件允许我们在后台代码当中进行处理相应的逻辑. 介绍事件 在Razor组件中, 同样提供了事件处理功能.对于具有委托类型值且名为 @on {EVENT}(例如 @onclick)的 HTML 元素特性,Razor 组件将该特性的值视为事件处

  • Blazor路由与页面导航开发介绍

    在 Blazor 中,应用中的每个页面都是一个组件,通常在 razor 文件中定义,具有一个或多个指定路由. 路由大多数发生在客户端,而不涉及特定的服务器请求. 浏览器首先发出对应用程序根地址的请求. 然后, Blazor 应用中的根 Router 组件会处理截获导航请求,并将它们处理到正确的组件. Blazor 中的路由由 Router 组件处理. Router 组件通常在应用程序的根组件( App.Razor )中使用. Router 下面是VisualStudio创建的默认App.Razo

  • Blazor数据绑定用法

    Blazor当中, 类似实现了WPF的基础绑定功能, 支持在HTML元素当中使用Razor语法进行绑定C#字段.属性或 Razor 表达式值. 绑定语法 在Html标签中,使用Razor的语法, 前缀使用@符号, 然后添加 @bind="xxxx" 即可实现最简单的绑定, 如下: input @bind="Name" /> @code { private string Name{ get; set; } } 通过上面的操作, Input中的值与属性Name则进

  • Blazor页面组件用法介绍

    Blazor应用中, 是使用组件来构建用户界面, 例如页面.窗口.对话框等. 组件 使用C#和HTML标记的组合, Blazor组件称之为Razor组件, 文件名以 (.razor)结尾的文件. 1.如下所示, 在VisualStudio创建Blazor应用模板后的截图, 展示了Page文件夹中定义的razor文件. 注意:所有的Blazor组件, 都必须大写字符开头, 否则无效.如上图所示 ↑ 2.关于.razor 页面 对于每个 .razor页面来说, 包含了两个部分: 1. Html标记的

  • Blazor实现数据验证

    Blazor 提供一组输入组件. 输入组件会将绑定字段数据处理到模型,并在提交窗体时验证用户输入.下表显示了可用的输入组件: EditForm EditForm 组件通过 EditContext 包装这些输入组件并协调验证过程. 创建 EditForm 时,可以使用 Model 参数指定要绑定到的模型实例. 验证通常是使用数据批注完成的,并且可以进行扩展. 若要启用基于数据批注的验证,请将 DataAnnotationsValidator 组件添加为 EditForm 的子组件. EditFor

  • Blazor框架简介

    Blaozr 是由微软2019推出得一种使用.NET 生成交互式客户端得Web UI框架. 该框架利用C#代替JavaScript进行创建UI , 并且可以共享.NET编写的服务端和客户端业务代码. 优势: 1 使用C#代替JavaScript编写代码, 意味着, 如果你使用的是.Net进行编写服务端(例:ASP.NET Core WebApi) 或者是 客户端(WPF/Winform),那么可以共享应用之前的逻辑, 无需针对Web再编写其他的业务代码. 2 始终高效支持 Windows.Lin

  • ASP.NET Core中的Blazor组件介绍

    目录 关于组件 组件类 静态资产 路由与路由参数 组件参数 请勿创建会写入其自己的组参数属性的组件 子内容 属性展开 任意参数 捕获对组件的引用 在外部调用组件方法以更新状态 使用 @ 键控制是否保留元素和组件 指定基类 指定属性 导入组件 原始 HTML 项目 Blazor 中,使用 .razor 结尾的文件,称为组件:而 Blazor 中的组件,正式名称是 razor 组件: Blazor 组件是 razor 过渡而来的,使用 razor 的基本语法特性,但是 Balzor 不支持 razo

  • ASP.NET Core中的Razor页面介绍

    目录 简介 Why? 创建Razor页面应用程序 ASP.NETCoreRazor页面-核心功能 模型绑定 Handlers TagHelpersandHTMLHelpers 路由 总结 简介 随着ASP.NET Core 2 即将来临,最热门的新事物是Razor页面. Razor页面是ASP.NET Core的一个新功能,可以使基于页面的编程方式更容易,更高效. 大众的初步印象是对于那些只专注于页面的小型应用来说,Razor页面更容易.更快地取代MVC.然而,事实证明,它可能比这更强大.使用A

  • ASP.NET Core中的对象池介绍

    asp.net core中通过扩展库的方式提供给了一个标准的对象池ObjectPool,定义在Microsoft.Extensions.ObjectPool.dll 程序集中.它本身是个纯虚的抽象类,它就定义了两个接口函数,实现如下 public abstract class ObjectPool<T> where T : class { public abstract T Get(); public abstract void Return(T obj); } 这是一个比较典型的对象池接口:

  • ASP.NET Core中的静态文件介绍

    静态文件(HTML,CSS,图片和Javascript之类的资源)会被ASP.NET Core应用直接提供给客户端. 静态文件通常位于网站根目录(web root) <content-root>/wwwroot文件夹下.通常会把项目的当前目录设置为Content root,这样项目的web root就可以在开发阶段被明确. public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.Create

  • ASP.NET Core中的Caching组件简介

    在.NET Core中提供了Caching的组件.目前Caching组件提供了三种存储方式: Memory Redis SQLSever 1.Memeor Caching 新建一个ASP.NET Core Web应用程序项目,然后安装 Microsoft.Extensions.Caching.Memory. 修改ConfigureServices方法 services.AddMemoryCache(); services.AddMvc().SetCompatibilityVersion(Comp

  • ASP.NET Core中的Ocelot网关介绍

    目录 1.简介 2.Ocelot配置 2.1基础集成(Basic Implementation) 2.2集成IdentityServer(With IdentityServer) 2.3多个网关实例集群(Multiple Instances) 2.4集成Consul服务发现(With Consul) 2.5集成Service Fabric(With Service Fabric) 3.总结 1.简介 Ocelot原本设计仅为与.NET Core一起使用的,它是一个.NET API网关,作为面向使

  • Asp.net core前端框架Blazor介绍

    一.Blazor介绍 Blazor是微软在Asp.net core 3.0中推出的一个前端MVVM模型,它可以利用Razor页面引擎和C#作为脚本语言来构建WEB页面. 在.Net5中,Blazor将代替传统的Web Pages.可以代替如下代码简单演示了它的基本功能: 和Angular JS和VUE的模型非常类似,Blazor 支持大多数应用所需的核心方案: 参数 事件处理 数据绑定 路由 依赖关系注入 布局 模板 级联值 使用Blazor主要有如下好处: C# 语言:使用 C# 代替 Jav

  • ASP.NET Core中Razor页面与MVC区别介绍

    作为.NET Core 2.0发行版的一部分,还有一些ASP.NET的更新.其中之一是添加了一个新的Web框架来创建“页面”,而不需要复杂的ASP.NET MVC.新的Razor页面是一个比较简单的MVC框架版本,在某些方面是老的“.aspx” WebForms的演变. 在本文中,我们将介绍使用ASP.NET Razor页面和MVC的一些细节. Razor页面基础知识 ASP.NET MVVM vs MVC Razor页面的优点和缺点 使用Handlers实现多个GET.POST Action方

  • ASP.NET Core中的Razor页面使用视图组件

    视图组件简介 在新的ASP.NET Core MVC中,视图组件类似于局部视图,但它们更强大.视图组件不使用模型绑定,仅依赖于您在调用时提供的数据. 视图组件特性: 呈现页面响应的某一部分而不是整个响应 包括在控制器和视图之间发现的关注分离和可测试性优势 可以具有参数和业务逻辑 通常在页面布局中调用 视图组件是在任何地方可重用的呈现逻辑,对于局部视图来说相对复杂,例如: 动态导航菜单 标签云(查询数据库) 登录面板 购物车 最近发表的文章 典型博客上的侧边栏内容 将在每个页面上呈现的登录面板,并

  • ASP.NET Core中使用xUnit进行单元测试

    单元测试的功能自从MVC的第一个版本诞生的时候,就是作为一个重要的卖点来介绍的,通常在拿MVC与webform比较的时候,单元测试就是必杀底牌,把webform碾压得一无是处. 单元测试的重要性不用多说了,有单元测试的做兜底的项目,好比给开发人员买了份保险,当然这个保险的质量取决于单元测试的质量,那些一路Mock的单元测试,看起来很美,但是什么都cover不到.目前工作中的一个老项目,有2万多个单元测试用例,其中不少是用心之作,真正落实到了业务逻辑,开发人员可以放心的去修改代码,当然一切都必须按

随机推荐