Blazor中如何渲染作为属性传入的子组件,有没有类似Angular ng-content的方案?
问题根因
你当前的写法输出类型名,是因为Blazor不会直接渲染手动实例化的ComponentBase对象,直接放到Razor模板中时只会调用其ToString()方法输出类型全名;同时手动实例化组件不符合Blazor的生命周期管理规则,无法完成参数绑定、事件注册等正常逻辑,属于错误用法。
Blazor中对应Angular ng-content的方案是使用RenderFragment实现内容插槽,我们可以基于这个特性实现同时兼容两种使用方式的Row组件。
最优实现方案(兼容两种使用方式)
1. 定义Column子组件
用于接收标记式写法中的列内容:
// Column.razor @code { [CascadingParameter] private Row ParentRow { get; set; } [Parameter] public RenderFragment ChildContent { get; set; } protected override void OnInitialized() { ParentRow?.AddColumn(this); } }
2. 实现Row组件
// Row.razor <div class="row"> @* 渲染标记式传入的列 *@ @foreach (var column in Columns) { <div class="col-6"> @column.ChildContent </div> } @* 兼容编程式传入的列 *@ @if (Columns.Count == 0) { @if (Column1 != null) { <div class="col-6">@Column1</div> } @if (Column2 != null) { <div class="col-6">@Column2</div> } } </div> @code { internal List<Column> Columns { get; set; } = new(); [Parameter] public RenderFragment Column1 { get; set; } [Parameter] public RenderFragment Column2 { get; set; } [Parameter] public RenderFragment ChildContent { get; set; } internal void AddColumn(Column column) { Columns.Add(column); } protected override void OnParametersSet() { Columns.Clear(); ChildContent?.Invoke(); } }
两种使用方式示例
标记式写法(类似Angular ng-content效果)
和你要求的写法完全一致:
<Row> <Column> <Foo></Foo> </Column> <Column> <Bar></Bar> </Column> </Row>
编程式传入组件写法
不需要手动实例化组件,直接定义渲染片段即可:
<Row Column1="@fooContent" Column2="@barContent"></Row> @code { private RenderFragment fooContent = @<Foo />; private RenderFragment barContent = @<Bar />; }
补充说明
如果需要动态渲染未知类型的组件,可以结合Blazor内置的DynamicComponent实现:
<Row Column1="@RenderComponent(typeof(Foo))" Column2="@RenderComponent(typeof(Bar))"></Row> @code { private RenderFragment RenderComponent(Type componentType) => @<DynamicComponent Type="@componentType" />; }
内容的提问来源于stack exchange,提问作者Matthew Layton
相关产品推荐
相关产品推荐

