Blazor入门:ASP.NET Core Razor 组件
官方文档原文位置:
https://docs.microsoft.com/zh-cn/aspnet/core/blazor/components?view=aspnetcore-3.1
本文并不是独立教程的文章,而是属于对微软文档的讲解和说明。
组件:项目 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>";
}
Blazor入门:ASP.NET Core Razor 组件的更多相关文章
- Blazor入门笔记(6)-组件间通信
1.环境 VS2019 16.5.1.NET Core SDK 3.1.200Blazor WebAssembly Templates 3.2.0-preview2.20160.5 2.简介 在使用B ...
- C# -- HttpWebRequest 和 HttpWebResponse 的使用 C#编写扫雷游戏 使用IIS调试ASP.NET网站程序 WCF入门教程 ASP.Net Core开发(踩坑)指南 ASP.Net Core Razor+AdminLTE 小试牛刀 webservice创建、部署和调用 .net接收post请求并把数据转为字典格式
C# -- HttpWebRequest 和 HttpWebResponse 的使用 C# -- HttpWebRequest 和 HttpWebResponse 的使用 结合使用HttpWebReq ...
- .NET Core实战项目之CMS 第二章 入门篇-快速入门ASP.NET Core看这篇就够了
作者:依乐祝 原文链接:https://www.cnblogs.com/yilezhu/p/9985451.html 本来这篇只是想简单介绍下ASP.NET Core MVC项目的(毕竟要照顾到很多新 ...
- net core体系-web应用程序-4asp.net core2.0 项目实战(CMS)-第二章 入门篇-快速入门ASP.NET Core看这篇就够了
.NET Core实战项目之CMS 第二章 入门篇-快速入门ASP.NET Core看这篇就够了 原文链接:https://www.cnblogs.com/yilezhu/p/9985451.ht ...
- ASP.NET Core - Razor 页面简介
简介 随着ASP.NET Core 2 即将来临,最热门的新事物是Razor页面.在之前的一篇文章中,我们简要介绍了ASP.NET Core Razor 页面. Razor页面是ASP.NET Cor ...
- ASP.NET Core Razor 页面使用指南
ASP.NET Core Razor 页面作为 ASP.NET Core 2.0的一部分发布,它是基于页面的全新的Web开发框架.如果您想学习如何使用 ASP.NET Core Razor 页面,可以 ...
- 学习ASP.NET Core Razor 编程系列一
一. 概述 .NET Core 1.0发布的时候就想进行学习的,不过根据微软的以往的发布规律1.0版可以认为是大众测试版,2.0才算稳定.现在2.1都已经发布了预览版,之前对其"不稳定&qu ...
- 学习ASP.NET Core Razor 编程系列六——数据库初始化
学习ASP.NET Core Razor 编程系列目录 学习ASP.NET Core Razor 编程系列一 学习ASP.NET Core Razor 编程系列二——添加一个实体 学习ASP.NET ...
- ASP.Net Core Razor+AdminLTE 小试牛刀
AdminLTE 一个基于 bootstrap 的轻量级后台模板,这个前端界面个人感觉很清爽,对于一个大后端的我来说,可以减少较多的时间去承担前端的工作但又必须去独立去完成一个后台系统开发的任务,并且 ...
随机推荐
- 安卓广播api介绍,给自己理清楚概念
广播接收器类概述 这是用于接收由sendBroadcast()发送intent的基类.这个类一般都会被继承重写里面的onReceive()方法..如果您不需要跨应用程序发送广播,请考虑使用LocalB ...
- jquery 延迟执行方法
setTimeout方法使用时需注意: //以下两种方式都行: setTimeout(function () { test(); }, ); //或者 setTimeout(); function t ...
- 【LeetCode】 99. Recover Binary Search Tree [Hard] [Morris Traversal] [Tree]
Two elements of a binary search tree (BST) are swapped by mistake. Recover the tree without changing ...
- 详解 NIO流
在观看本篇博文前,建议先观看本人博文 -- <详解 IO流> NIO流: 首先,本人来介绍下什么是NIO流: 概述: Java NIO ( New IO )是从 Java 1.4 版本开始 ...
- vue使用trackingjs
前言:因为公司是做人工智能-AI的,所有一个web数据平台为了装X,需要做个人脸登陆.前台需要把人脸的base64发给后台去做人脸校验. 功能很简单,需要注意的是web需要实现“调用摄像头”和“自动拍 ...
- Springboot:thymeleaf模板(八)
存放位置:resources\templates 访问方式:通过Controller请求访问,不可直接访问(相当于web项目的WEB-INF目录) 环境依赖: <!--thymeleaf模板支持 ...
- 总结vscode调试vue,nodejs的各种方法
之前写项目一直都是console.log()来调试的,浪费了很多时间,现在整理一下用vscode对nuxt(vue)前后端进行调试的方法 前端的调试 chrome+launch 使用chrome调试, ...
- EasyPoi 导入导出Excel时使用GroupName的踩坑解决过程
一.开发功能介绍: 简单的一个excel导入功能 二.Excel导入模板(大致模板没写全): 姓名 性别 生日 客户分类 联系人姓名 联系人部门 备注 材料 综合 采购 张三 男 1994/05/25 ...
- C# 基础知识系列-13 常见类库(三)
0. 前言 在<C# 基础知识系列- 13 常见类库(二)>中,我们介绍了一下DateTime和TimeSpan这两个结构体的内容,也就是C#中日期时间的简单操作.本篇将介绍Guid和Nu ...
- 笔记-VUE滚动加载更多数据
来源:https://blog.csdn.net/qq_17281881/article/details/87342403 VUE滚动加载更多数据 data() { return { loading: ...