===========================================
参考
===========================================
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; }
}
效果: