ASP.NET|ASP.NET Core中的Blazor组件介绍
项目 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)等,默认寻址时,使用绝对路径
/
即可访问资源。例如:
文章图片
这个路径是要放到前端才能,由前端访问时 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}"@Id@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 文件内容:
@Title@code{[Parameter]public string Title { get; set; } = "test"; }
别的组件嵌入
Test.razor
这个组件时,就可以使用 Title 传递参数进去:请勿创建会写入其自己的组参数属性的组件 前面我们说到,
[Parameter]
特性的使用,这个特性时作为参数传递而使用的。对于路由参数,其修饰的属性应该是
privite
,对于其它组件传递参数,属性应该设置为 public
。如果一个组件的
@code{}
成员不需要被外界作为参数使用,就应该设置为 private
。因为
.razor
一般不会作为类来使用。、;而且不设置 [Parameter]
的属性,别的组件也使用不了这个属性。【ASP.NET|ASP.NET Core中的Blazor组件介绍】那么,文档说 “请勿创建会写入其自己的组参数属性的组件”,指定是
[Parmeter]
休息的属性,是作为参数传递使用的,不要在组件中修改这个属性的值。如果实在要操作的话,可以先拷贝这个值,使用别的变量操作,示例:
@Title@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
中,内容:@Children@code{[Parameter]public RenderFragment Children { get; set; }}
另一个组件:
@page "/"@code{private RenderFragment r =@测试子内容; }
RenderFragment
的使用,请自行查阅资料。属性展开 属性展开是使用字典类型表示一个 Html 标签的多个属性。
@code {#regionprivate 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 InputAttributes { get; set; } = new Dictionary(){{ "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 AdditionalAttributes { get; set; }}
父组件中使用:
B、C 都是
Test.razor
中没有出现过的,那么这些参数和参数值都会自动转为键值对存储到 AdditionalAttributes 中。测试示例:
Test.razor
中的内容@foreach (var item in AdditionalAttributes){
@code{// 这个属性没有用,随便起个名字测试[Parameter]public string TTT { get; set; }[Parameter(CaptureUnmatchedValues = true)]public IDictionary AdditionalAttributes { get; set; }}- @item.Key - @item.Value
}
其它组件使用:
@page "/"
捕获对组件的引用 组件引用提供了一种引用组件实例的方法,使用
@ref
可以实现引用对参数的引用。创建一个
Test.razor
文件,内容不限。在一个组件中,引用该组件实例
@page "/"@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 func){events += func; }public static void RemoveEvent(Func func){events -= func; }private static event Func events; }
在
Index.razor
中@page "/"@using BlazorApp1.Data@implements IDisposable@foreach (var item in messageList){
@code {private string _message; private List messageList = new List(); // 进入页面时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); }}- @item
}
打开多个窗口,访问页面
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 Notify; }
该类型的 Notify 可以绑定多个事件;通过调用
Update()
方法,可以触发各个事件。在 Startup 中注入服务
services.AddSingleton();
。Index.razor
中,内容为:@page "/"@using BlazorApp1.Data@inject NotifierService Notifier@implements IDisposableLast update: @_lastNotification.key = @_lastNotification.value
@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 NotifierKey:Value:@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 = https://www.it610.com/article/null; }}
然后启动项目,一个页面打开
https://localhost:5001/
,另一个页面打开 https://localhost:5001/test
。在
test
页面输入 Key 和 Value,点击按钮,即可通知到所有正在打开 Index.razor
的页面。使用 @ 键控制是否保留元素和组件 在使用表格或了表等元素时,如果出现插入或删除、更新等情况,整个表格或列表,就会被重新渲染。这样会带来比较大的性能消耗。
一般使用绑定的元素,其更新是自动的,不需要人为控制。
在能保证每一项的某个元素列,都是唯一的时候,我们可以使用
@key
关键字来优化组件。示例:
@page "/"@using BlazorApp1.DataKey:Value:@foreach (var item in dic){
@code {private int? _key; private int _value; private List- @item.Key - @item.Value
}dic { get; set; } = new List (); private void Add(){if (_key == null)return; dic.Add(new MyData{Key = _key.Value,Value = https://www.it610.com/article/_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)" Test "; }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
推荐阅读
- Windows|Windows Embedded Compact 7中的内存管理(下)
- Redis|Redis 中的过期删除策略和内存淘汰机制
- C#|从零开始手把手教你,.net 6用EF Core基本创建表,迁移到mysql数据库
- .NET|EF Core codefirst数据迁移操作
- Python中的列表及其操作方法
- ASP.NET的Core|ASP.NET的Core AD域登录过程示例
- 用户触达难(流失率高?HMS|用户触达难?流失率高?HMS Core预测服务和智能运营,助你提前掌握营销时机,解决此难题。)
- ASP.NET|ASP.NET Core MVC中Required与BindRequired用法与区别介绍
- Java|Java 超详细讲解数据结构中的堆的应用
- 如何通过一篇文章了解Python中的生成器