官方文档原文位置:

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 组件的更多相关文章

  1. Blazor入门笔记(6)-组件间通信

    1.环境 VS2019 16.5.1.NET Core SDK 3.1.200Blazor WebAssembly Templates 3.2.0-preview2.20160.5 2.简介 在使用B ...

  2. 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 ...

  3. .NET Core实战项目之CMS 第二章 入门篇-快速入门ASP.NET Core看这篇就够了

    作者:依乐祝 原文链接:https://www.cnblogs.com/yilezhu/p/9985451.html 本来这篇只是想简单介绍下ASP.NET Core MVC项目的(毕竟要照顾到很多新 ...

  4. 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 ...

  5. ASP.NET Core - Razor 页面简介

    简介 随着ASP.NET Core 2 即将来临,最热门的新事物是Razor页面.在之前的一篇文章中,我们简要介绍了ASP.NET Core Razor 页面. Razor页面是ASP.NET Cor ...

  6. ASP.NET Core Razor 页面使用指南

    ASP.NET Core Razor 页面作为 ASP.NET Core 2.0的一部分发布,它是基于页面的全新的Web开发框架.如果您想学习如何使用 ASP.NET Core Razor 页面,可以 ...

  7. 学习ASP.NET Core Razor 编程系列一

    一. 概述 .NET Core 1.0发布的时候就想进行学习的,不过根据微软的以往的发布规律1.0版可以认为是大众测试版,2.0才算稳定.现在2.1都已经发布了预览版,之前对其"不稳定&qu ...

  8. 学习ASP.NET Core Razor 编程系列六——数据库初始化

    学习ASP.NET Core Razor 编程系列目录 学习ASP.NET Core Razor 编程系列一 学习ASP.NET Core Razor 编程系列二——添加一个实体 学习ASP.NET ...

  9. ASP.Net Core Razor+AdminLTE 小试牛刀

    AdminLTE 一个基于 bootstrap 的轻量级后台模板,这个前端界面个人感觉很清爽,对于一个大后端的我来说,可以减少较多的时间去承担前端的工作但又必须去独立去完成一个后台系统开发的任务,并且 ...

随机推荐

  1. 对于之间不平凡的我,为什么会选择IT!(上)

    我相信有很多小伙伴看了我发布的文章后,不知道对大家有无启发,在这里我都非常感谢大家的收看,因为现在收疫情影响,我也看到很多朋友私信我,看你经历这么多是经历了什么,如果大家在上一篇发现的时候会看见我父亲 ...

  2. python编程语言是什么?它能做什么?

    Python是一种全栈的开发语言,你如果能学好Python,前端,后端,测试,大数据分析,爬虫等这些工作你都能胜任. 当下Python有多火我不再赘述,,Python有哪些作用呢? 就目前Python ...

  3. 2020不平凡的90天,Python分析三个月微博热搜数据带你回顾

    前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者:刘早起早起 PS:如有需要Python学习资料的小伙伴可以加点击下方链 ...

  4. stand up meeting 12/4/2015 -12/6/2015

    part 组员 今日工作 工作耗时/h 明日计划 工作耗时/h UI 冯晓云        ------  --- 数据库 朱玉影  等待张葳出关        0  foxit reader  6 ...

  5. 我用Python一键保存了半佛老师所有的骚气表情包

    本文首发于公众号「Python知识圈」,如需转载,请在公众号联系作者授权. 2019年发现两个有意思而且内容比较硬核的公众号.都是同一个人运营的,我们都叫他半佛老师,现实中的职业是风控,公众号内容涉及 ...

  6. leetcode-0617 合并二叉树

    题目地址https://leetcode-cn.com/problems/merge-two-binary-trees/ 1.递归解法 递归的话我们首先需要递归的终止条件,对于本题而言,递归的终止条件 ...

  7. Springboot:整合Mybaits和Druid【监控】(十一)

    MyBatis默认提供了一个数据库连接池PooledDataSource,在此我们使用阿里提供的Druid数据库连接池 项目下载:https://files.cnblogs.com/files/app ...

  8. 2020/4/26 大数据的zookeeper分布式安装

    大数据的zookeeper分布式安装 **** 前面的文章已经提到Hadoop的伪分布式安装.现在就在原有的基础上安装zookeeper. 首先启动Hadoop平台 [root@master ~]# ...

  9. Go gRPC进阶-gRPC转换HTTP(十)

    前言 我们通常把RPC用作内部通信,而使用Restful Api进行外部通信.为了避免写两套应用,我们使用grpc-gateway把gRPC转成HTTP.服务接收到HTTP请求后,grpc-gatew ...

  10. 高德局部刷新标记点,bug解决

    将接口返回的经纬集合点在高德地图上标记展示, 如果实时刷新地图标记点,不加优化,则会造成过多的带宽消耗 所以,地图只需加载一次,局部更新标记点就好了 代码: <template> < ...