最新要闻

广告

手机

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

家电

全球今日讯!打开MASA Blazor的正确姿势5:插槽

来源:博客园


(资料图片仅供参考)

依照Vuetify的习惯,MASABlazor将RenderFragment称为插槽。RenderFragment是Blazor的一个难点,而MASA Blazor是二次开发的组件库,大量使用到插槽,所以有必要掌握这个功能。注:在Blazor中,一般将RenderFragment称为模板。

一、插槽RenderFragment的定义和使用

组件式开发模式,带来了复用、灵活、性能等优势,但也增加了组件之间数据传递的复杂度。组件之间数据传递的方式一般包括以下四种:①通过属性实现父传子,②通过事件实现子传父,③通过插槽实现传递UI片断,④通过状态管理实现跨组件数据共享。

1、默认插槽

//子组件Child.razor//使用RenderFragment类型的属性参数,接收父组子传递过来的内容//@ChildContent就像是一个预留的插槽,具体渲染什么内容,由调用Child组件的父组件传入//父组件在使用Child组件时,传入具体的插槽内容,可以是普通文本、响应式数据、HTML原生元素、自定义组件及其任意组合//默认插槽,属性名称约定为ChildContent,不能使用其它名称
@ChildContent
@code { [Parameter] public RenderFragment? ChildContent { get; set; }}
//父组件Index.razor//在子组件Child的标签体位置,定义传入子组件插槽中的内容。【这个位置普通文本响应式数据:@msg    
任意HTML原生元素和自定义组件标签
@code { private string msg = "响应式数据";}

2、具名插槽

//子组件Child.razor//定义多个RenderFragment类型的属性参数(插槽)//具名插槽可以任意命名。而默认插槽则只能使用ChildContent
@Header
@Body
@Footer
@ChildContent
@code { [Parameter] public RenderFragment? Header { get; set; } [Parameter] public RenderFragment? Body { get; set; } [Parameter] public RenderFragment? Footer { get; set; } [Parameter] public RenderFragment? ChildContent { get; set; }}
//父组件Index.razor//使用标签方式传递具名插槽,标签名就是子组件的插槽名。    

这里是Header片断

这里是Body片断

这里是Footer片断

其它未具名的内容,都由默认插槽ChildContent接收

@code {}

3、RenderFragment的本质

  • RenderFragment的本质是一个委托,参数是RenderTreeBuilder对象
  • 源码【public delegate void RenderFragment(RenderTreeBuilder builder);】
  • RenderTreeBuilder是Blazor中用于渲染UI的对象
  • 在视图层调用@HelloContent,实际上就是在调用委托,而这个委托执行RenderTreeBuilder的一系列渲染UI的方法
  • RenderFragment委托的方法体,正是我们在默认插槽或具体插槽中传入组件的内容。
//以下三种方法是等效的//方法一:

hello world

//方法二:
@HelloContent
@code{ private RenderFragment HelloContent=(RenderTreeBuilder builder)=>{ builder.OpenElement(0,"h1"); builder.AddContent(1, "hello world"); builder.CloseElement(); };}//方法三://注意这种方式,参数名称必须为__builder
@HelloContent
@code { private RenderFragment HelloContent = (RenderTreeBuilder __builder) => {

hello world

};}

4、更复杂的泛型RenderFragment的本质

  • RenderFragment的本质可以理解为是委托的委托,返回值是一个RenderFragment
  • 源码【public delegate RenderFragment RenderFragment(TValue value);】
  • 在视图层调用@HelloContent("world"),将实参传入HelloContent委托
  • 通过这种方法,可以实现将数据从插槽传到父组件。
  • 泛型参数T可以是任意类型。
//将参数传入到委托的方法体中(如上我们知道,方法体中执行的一系列UI渲染,就是从父组件传入到插槽的内容)//HelloContent委托,定义形参msg//调用@HelloContent()时,传入实参
@HelloContent("world")
@code { private RenderFragment HelloContent = (msg) => (RenderTreeBuilder builder) => { builder.OpenElement(0, "div"); builder.AddContent(1, "hello " + msg); builder.CloseElement(); };}

5、泛型RenderFragment的小案例

//子组件Child.razor@ChildContent(msg)@code {    [Parameter]    public RenderFragment? ChildContent { get; set; }    private string msg = "hello world";}
//父组件Index.razor//获取子组件传递过来的msg,有两种方式//方式一:通过@context    
@context
/*方法二:通过定义Context属性 //msg可以任意命名
@msg
*/

6、泛型RenderFragment的进一步抽象:泛型参数还可以是泛型,不指定具体类型

//子组件Child.razor@typeparam T //定义泛型参数T@ChildContent((T)msg) //将msg强制转化为T泛型@code {    [Parameter]    public RenderFragment? ChildContent { get; set; }    private object msg = "hello world";}
//父组件Index.razor //指定泛型类型    
@context

二、MASA Blazor中插槽的应用

1、以简单的Dialogs为例,直接解读代码

Click Me 卡片标题 卡片内容
Dialog的API文档-插槽部分:

2、插槽应用最复杂的应该是Table组件,有机会可以读一下源码

关键词: 具体类型 大量使用