深入浅出Blazor webassembly之理解ChildContent RenderFragment

===========================================

参考

===========================================

https://blazor-university.com/templating-components-with-renderfragements/

https://docs.microsoft.com/en-us/aspnet/core/blazor/components/templated-components

===========================================

背景

===========================================

普通组件的使用示例, 注意仅仅包含组件的IncrementAmount 参数, 不能包含子html内容或子tag.

<Counter IncrementAmount="5"/>

Counter组件的定义代码:

@page "/counter" 

<h1>Counter</h1>

<p>Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {

    [Parameter] public int IncrementAmount{ get; set; } = 1;

    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount= currentCount+ IncrementAmount;
    }
}

这样的简单组件, 在被使用时不允许添加inner html内容, 组件的html都由组件自身确定, 外界仅仅能输入一些参数.

如果在使用这样的组件时, 硬要加inner html, 运行时会报错.

@page "/simplepage"
<Counter IncrementAmount="5">something</Counter>

===========================================

带 RenderFragment 的组件

===========================================

如果我们要让 Counter 组件要对外开放html样式控制,   比如 IncrementAmount <10, 用 h1 样式; IncrementAmount <20 用h2 样式;   IncrementAmount <30 用h3 样式;  上面实现方式的组件做起来就很不灵活了, 就非常不便.

Blazor提供一个好的解决方式是, 即带有 RenderFragment 的组件.  需要说明的是, RenderFragment 类型实际上是一个delegate 代理, 以后再细讲这个.

关于组件增加  RenderFragment 参数的规则是:

  • (1)如果组件带有inner html 就必须为组件增加 RenderFragment 参数.
  • (2)如果使用组件时, inner html 是直接放到组件tag之下, 则组件一定要有 ChildContent RenderFragment 参数, 否则运行报错. 
  • (3)如果使用组件时, inner html是放到某个自定义tag下, 则组件必须定义一个和tag同名的RenderFragment 参数 或 ChildContent RenderFragment 参数. Blazor 优先为同名的RenderFragment 参数赋值, 如果没有的话, 会试图为ChildContent参数赋值, 如果ChildContent参数也不存在的话, 就会运行报错. 
  • (4)组件定义中多RenderFragment 参数, 运行不会有问题, 但如果少定义了 RenderFragment 参数,运行就会报错
  • (5)为了防止使用方多传子tag,  所有自定义的组件最好都声明一个 ChildContent RenderFragment 参数

规则(2)的示例说明:

@page "/simplepage"
<Counter IncrementAmount="5">
    <h1>something</h1>
</Counter>

<Counter IncrementAmount="5">something</Counter>
@page "/counter" 
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@ChildContent 
@code {

    [Parameter] public int IncrementAmount{ get; set; } = 1;
    [Parameter] public RenderFragment ChildContent { get; set; } //必需名为ChildContent 

    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount= currentCount+ IncrementAmount;
    }
}

规则(3)的示例说明:

@page "/simplepage"
<Counter IncrementAmount="5">
    <ChildContent2>something</ChildContent2>
</Counter>
@page "/counter"
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
<br />
ChildContent: @ChildContent
<br />
ChildContent2: @ChildContent2
@code {

    [Parameter] public int IncrementAmount { get; set; } = 1;
    [Parameter] public RenderFragment ChildContent { get; set; }  //增加ChildContent参数, 保险起见
    [Parameter] public RenderFragment ChildContent2 { get; set; } //优先被赋值

    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount = currentCount + IncrementAmount;
    }
}

运行效果:

===========================================

带多个 RenderFragment 参数组件的示例

===========================================

RenderFragment 参数非常适合模版型组件开发, 比如我们要设计一个 Modal Dialog 组件, 该组件大块显示内容都由外界传入, 比如Header/Content/Footer, 另外为了增加通用性, 样式控制最好开放使用方.

@page "/simplepage"

<MyModal>
    <Header>this is title</Header>
    <Content>This is content</Content>
    <Footer>
        <button type="button" class="btn btn-primary"> Close Dialog </button>
    </Footer>
</MyModal>
@Header 
<br />
@Content 
<br />
@Footer   

@code {
    [Parameter] public RenderFragment Header { get; set; }
    [Parameter] public RenderFragment Content { get; set; }
    [Parameter] public RenderFragment Footer { get; set; }
    [Parameter] public RenderFragment ChildContent { get; set; }
}

效果:

原文地址:https://www.cnblogs.com/harrychinese/p/blazor_childcontent.html