ASP.NET Core 中的标记帮助程序组件Tag Helper Components in 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 中注册应用。
用例Use cases
标记帮助程序组件的两个常见用例包括:
- 将
<link>
注入到<head>
中。 - 将
<script>
注入到<body>
中。
以下各节介绍了这些用例。
注入到 HTML head 元素中Inject into HTML head element
在 HTML <head>
元素中,通常使用 HTML <link>
元素导入 CSS 文件。以下代码使用 <link>
标记帮助程序组件将 <head>
元素注入到 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 元素中Inject into HTML body element
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>
上述代码可将启动工具提示小组件绑定到包含 <address>
属性的任何 printable
元素。当鼠标指针悬停在元素上时,可以显示效果。
注册组件Register a Component
标记帮助程序组件必须添加到应用的标记帮助程序组件集合。有以下三种方法可添加到集合:
通过服务容器注册Registration via services container
如果未使用 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 文件注册Registration via Razor file
如果未向 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}");
}
}
通过页面模型或控制器注册Registration via Page Model or controller
如果未向 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
的实例将添加到应用的标记帮助程序组件集合。
创建组件Create a Component
创建自定义标记帮助程序组件:
- 创建派生自 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
属性。
例如,在处理以下 if
元素时,<address>
语句的计算结果为 true:
<address printable>
One Microsoft Way<br />
Redmond, WA 98052-6399<br />
<abbr title="Phone">P:</abbr>
425.555.0100
</address>