- Razor页面
- 通用
- 客户端开发
- 标记帮助程序
- 高级
ASP.NET Core 中的标记帮助程序组件
作者:Scott Addie 和 Fiyaz Bin Hasan
标记帮助程序组件是可用于有条件地修改或添加服务器端代码中的 HTML 元素的标记帮助程序。 ASP.NET Core 2.0 或更高版本中提供了此功能。
ASP.NET Core 包括两个内置标记帮助程序组件:head
和 body
。 它们位于 Microsoft.AspNetCore.Mvc.Razor.TagHelpers 命名空间中,可用于 MVC 和 Razor Pages。 标记帮助程序组件不需要在 _ViewImports.cshtml 中注册应用。
用例
标记帮助程序组件的两个常见用例包括:
以下各节介绍了这些用例。
注入到 HTML head 元素中
在 HTML <head>
元素中,通常使用 HTML <link>
元素导入 CSS 文件。 以下代码使用 head
标记帮助程序组件将 <link>
元素注入到 <head>
元素中:
using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.TagHelpers; namespace RazorPagesSample.TagHelpers { public class AddressStyleTagHelperComponent : TagHelperComponent { private readonly string _style = @"<link rel=""stylesheet"" href=""/css/address.css"" />"; public override int Order => 1; public override Task ProcessAsync(TagHelperContext context, TagHelperOutput output) { if (string.Equals(context.TagName, "head", StringComparison.OrdinalIgnoreCase)) { output.PostContent.AppendHtml(_style); } return Task.CompletedTask; } } }
在上述代码中:
AddressStyleTagHelperComponent
可实现 TagHelperComponent。 抽象:- 允许初始化带有 TagHelperContext 的类。
- 启用标记帮助程序组件以添加或修改 HTML 元素。
- Order 属性可定义呈现组件的顺序。 应用中的标记帮助程序组件有多种用法时,
Order
是必需的。 - ProcessAsync 会将执行上下文的 TagName 属性值与
head
进行比较。 如果比较的计算结果为 true,则_style
字段的内容将注入到 HTML<head>
元素中。
注入到 HTML body 元素中
body
标记帮助程序组件可以将 <script>
元素注入到 <body>
元素中。 以下代码演示了此项技术:
using System; using System.IO; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.TagHelpers; namespace RazorPagesSample.TagHelpers { public class AddressScriptTagHelperComponent : TagHelperComponent { public override int Order => 2; public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) { if (string.Equals(context.TagName, "body", StringComparison.OrdinalIgnoreCase)) { var script = await File.ReadAllTextAsync( "TagHelpers/Templates/AddressToolTipScript.html"); output.PostContent.AppendHtml(script); } } } }
单独的 HTML 文件用于存储 <script>
元素。 HTML 文件使代码更清洁且更易于维护。 上述代码可读取 TagHelpers/Templates/AddressToolTipScript.html 的内容并将其追加到标记帮助程序输出中。 AddressToolTipScript.html 文件包括以下标记:
<script> $("address[printable]").hover(function() { $(this).attr({ "data-toggle": "tooltip", "data-placement": "right", "title": "Home of Microsoft!" }); }); </script>
上述代码可将启动工具提示小组件绑定到包含 printable
属性的任何 <address>
元素。 当鼠标指针悬停在元素上时,可以显示效果。
注册组件
标记帮助程序组件必须添加到应用的标记帮助程序组件集合。 有以下三种方法可添加到集合:
通过服务容器注册
如果未使用 ITagHelperComponentManager 管理标记帮助程序组件类,则必须向依赖关系注入 (DI) 系统注册。 以下 Startup.ConfigureServices
代码可注册带有瞬态生存期的 AddressStyleTagHelperComponent
和 AddressScriptTagHelperComponent
类:
public void ConfigureServices(IServiceCollection services) { services.Configure<CookiePolicyOptions>(options => { options.CheckConsentNeeded = context => true; options.MinimumSameSitePolicy = SameSiteMode.None; }); services.AddMvc() .SetCompatibilityVersion(CompatibilityVersion.Version_2_1); services.AddTransient<ITagHelperComponent, AddressScriptTagHelperComponent>(); services.AddTransient<ITagHelperComponent, AddressStyleTagHelperComponent>(); }
通过 Razor 文件注册
如果未向 DI 注册标记帮助程序组件,则可以从 Razor Pages 页或 MVC 视图注册。 此项技术用于控制注入的标记和 Razor 文件中的组件执行顺序。
ITagHelperComponentManager
用于添加标记帮助程序组件或从应用中删除这些组件。 以下代码演示了使用 AddressTagHelperComponent
的此项技术:
@using RazorPagesSample.TagHelpers; @using Microsoft.AspNetCore.Mvc.Razor.TagHelpers; @inject ITagHelperComponentManager manager; @{ string markup; if (Model.IsWeekend) { markup = "<em class='text-warning'>Office closed today!</em>"; } else { markup = "<em class='text-info'>Office open today!</em>"; } manager.Components.Add(new AddressTagHelperComponent(markup, 1)); }
在上述代码中:
@inject
指令提供了ITagHelperComponentManager
的实例。 该实例将分配到名为manager
的变量以访问 Razor 文件中的下游。AddressTagHelperComponent
的实例将添加到应用的标记帮助程序组件集合。
修改 AddressTagHelperComponent
以适应接受 markup
和 order
参数的构造函数:
private readonly string _markup; public override int Order { get; } public AddressTagHelperComponent(string markup = "", int order = 1) { _markup = markup; Order = order; }
提供的 markup
参数用于 ProcessAsync
,如下所示:
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) { if (string.Equals(context.TagName, "address", StringComparison.OrdinalIgnoreCase) && output.Attributes.ContainsName("printable")) { TagHelperContent childContent = await output.GetChildContentAsync(); string content = childContent.GetContent(); output.Content.SetHtmlContent( $"<div>{content}<br>{_markup}</div>{_printableButton}"); } }
通过页面模型或控制器注册
如果未向 DI 注册标记帮助程序组件,则可以从 Razor Pages 页面模型或 MVC 控制器注册。 此项技术可用于将 C# 逻辑与 Razor 文件隔离。
构造函数注入用于访问 ITagHelperComponentManager
的实例。 标记帮助程序组件将添加到该实例的标记帮助程序组件集合。 以下 Razor Pages 页面模型演示了使用 AddressTagHelperComponent
的此项技术:
using System; using Microsoft.AspNetCore.Mvc.Razor.TagHelpers; using Microsoft.AspNetCore.Mvc.RazorPages; using RazorPagesSample.TagHelpers; public class IndexModel : PageModel { private readonly ITagHelperComponentManager _tagHelperComponentManager; public bool IsWeekend { get { var dayOfWeek = DateTime.Now.DayOfWeek; return dayOfWeek == DayOfWeek.Saturday || dayOfWeek == DayOfWeek.Sunday; } } public IndexModel(ITagHelperComponentManager tagHelperComponentManager) { _tagHelperComponentManager = tagHelperComponentManager; } public void OnGet() { string markup; if (IsWeekend) { markup = "<em class='text-warning'>Office closed today!</em>"; } else { markup = "<em class='text-info'>Office open today!</em>"; } _tagHelperComponentManager.Components.Add( new AddressTagHelperComponent(markup, 1)); } }
在上述代码中:
- 构造函数注入用于访问
ITagHelperComponentManager
的实例。 AddressTagHelperComponent
的实例将添加到应用的标记帮助程序组件集合。
创建组件
创建自定义标记帮助程序组件:
- 创建派生自 TagHelperComponentTagHelper 的公共类。
- 将
[HtmlTargetElement]
属性应用于该类。 指定目标 HTML 元素的名称。 - 可选:将
[EditorBrowsable(EditorBrowsableState.Never)]
属性应用于类,以取消在 IntelliSense 中显示类型。
以下代码可创建面向 <address>
HTML 元素的自定义标记帮助程序组件:
using System.ComponentModel; using Microsoft.AspNetCore.Mvc.Razor.TagHelpers; using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.Extensions.Logging; namespace RazorPagesSample.TagHelpers { [HtmlTargetElement("address")] [EditorBrowsable(EditorBrowsableState.Never)] public class AddressTagHelperComponentTagHelper : TagHelperComponentTagHelper { public AddressTagHelperComponentTagHelper( ITagHelperComponentManager componentManager, ILoggerFactory loggerFactory) : base(componentManager, loggerFactory) { } } }
按如下所示使用自定义 address
标记帮助程序组件注入 HTML 标记:
public class AddressTagHelperComponent : TagHelperComponent { private readonly string _printableButton = "<button type='button' class='btn btn-info' onclick=\"window.open(" + "'https://binged.it/2AXRRYw')\">" + "<span class='glyphicon glyphicon-road' aria-hidden='true'></span>" + "</button>"; public override int Order => 3; public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) { if (string.Equals(context.TagName, "address", StringComparison.OrdinalIgnoreCase) && output.Attributes.ContainsName("printable")) { var content = await output.GetChildContentAsync(); output.Content.SetHtmlContent( $"<div>{content.GetContent()}</div>{_printableButton}"); } } }
上述 ProcessAsync
方法可将向 SetHtmlContent 提供的 HTML 注入到匹配的 <address>
元素中。 在以下情况下进行注入:
- 执行上下文的
TagName
属性值等于address
。 - 相应的
<address>
元素具有printable
属性。
例如,在处理以下 <address>
元素时,if
语句的计算结果为 true:
<address printable> One Microsoft Way<br /> Redmond, WA 98052-6399<br /> <abbr title="Phone">P:</abbr> 425.555.0100 </address>