ASP.NET Core MVC非Blazor下如何实现可复用HTML组件
ASP.NET Core MVC 没有 Blazor 原生的 RenderFragment 类型,但有成熟方案可以实现完全一致的可复用组件效果,其中最匹配你需求的是 Tag Helper 方案,语法和你想要的组件写法几乎无差别。
方案1:Tag Helper(最推荐,语法最接近Blazor组件)
这是最贴合你预期使用方式的实现,最终调用语法和你写的Blazor组件示例完全一致,不需要写复杂的调用逻辑,非开发背景的设计人员也能快速看懂。
- 编写自定义Tag Helper类,不要使用Blazor专属的
RenderFragment类型,直接通过内置API读取标签包裹的子内容即可:
// 标记目标标签为<card>,支持自闭合和正常闭合写法 [HtmlTargetElement("card", TagStructure = TagStructure.NormalOrSelfClosing)] public class CardTagHelper : TagHelper { // 对应组件的Title参数 public string Title { get; set; } public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) { // 读取标签包裹的所有子内容,等效于Blazor的ChildContent var innerContent = await output.GetChildContentAsync(); // 配置输出的外层标签和样式 output.TagName = "div"; output.Attributes.SetAttribute("class", "card card-px-0 shadow-sm"); // 拼接完整的卡片结构,后续Bootstrap版本升级只需要改这里的结构 output.Content.SetHtmlContent( new HtmlContentBuilder() .AppendHtml($@" <div class=""card-header""> <h3 class=""card-title"">{Title}</h3> <div class=""card-toolbar""> <button type=""button"" class=""btn btn-sm btn-light"">Action</button> </div> </div> <div class=""card-body"">") .AppendHtml(innerContent) .AppendHtml(@" </div> <div class=""card-footer"">Footer</div>") ); } }
- 在视图共享导入文件
_ViewImports.cshtml中添加Tag Helper注册,替换成你自己的项目程序集名称即可:
@addTagHelper *, YourProjectAssemblyName
- 之后在任意视图中可以直接用你想要的标签语法调用:
<card title="Section Title"> <p>I'm the body and would render inside the `ChildContent` area!</p> </card>
如果需要实现多个命名内容片段(类似Blazor的具名RenderFragment),只需要新增对应嵌套标签的Tag Helper即可,比如自定义card-footer标签传入自定义页脚内容,扩展非常灵活。
方案2:局部视图(Partial View)+ 模板委托
如果不想编写独立的Tag Helper类,也可以用局部视图配合Razor模板委托实现内容传入:
- 新建局部视图
Views/Shared/_Card.cshtml,定义接收的参数:
@model CardComponentModel <div class="card card-px-0 shadow-sm"> <div class="card-header"> <h3 class="card-title">@Model.Title</h3> <div class="card-toolbar"> <button type="button" class="btn btn-sm btn-light">Action</button> </div> </div> <div class="card-body"> @* 渲染传入的内容模板 *@ @Model.ContentTemplate(null) </div> <div class="card-footer">Footer</div> </div>
- 定义对应的参数模型:
public class CardComponentModel { public string Title { get; set; } // 用Razor原生的模板委托替代RenderFragment public Func<dynamic, IHtmlContent> ContentTemplate { get; set; } }
- 视图中调用方式如下:
@{ var cardData = new CardComponentModel { Title = "Section Title", ContentTemplate = @<p>I'm the body content!</p> }; } <partial name="_Card" model="cardData" />
这个方案的缺点是调用语法不如Tag Helper直观,适合结构非常简单的复用场景。
其他方案说明
- 你之前尝试的ViewComponent无法实现效果,核心原因是
RenderFragment是Blazor专属的类型,MVC视图渲染管线不识别这个类型。如果一定要用ViewComponent,可以把ContentTemplate的类型换成IHtmlContent,调用时手动将子内容转为HTML字符串传入,但写法非常繁琐,远不如Tag Helper简洁,不推荐使用。 - 你提到的
@helper语法在新版ASP.NET Core中已经被正式移除,不要在新项目中使用。
内容的提问来源于stack exchange,提问作者Scott Salyer
相关产品推荐
相关产品推荐

