.net core Razor视图的TagHelper使用方法介绍


TagHelper

TagHelper是ASP.NET 5的一个新特性。也许在你还没有听说过它的时候, 它已经在技术人员之间引起了大量讨论,甚至有一部分称它为服务器控件的回归。实际上它只不过是一个简化版本,把HTML和服务器内容混合在一起,没有控件生命周期,状态保持和事件。它不像服务器控件那样,对页面所有内容都具有访问权限。它只能访问到自己所生成的内容。

在 Razor 文件中,Tag Helpers 能够让服务端代码参与创建和渲染 HTML 元素。
Tag Helpers通过丰富的智能感知环境来创建 HTML 和 Razor 标记,为我们提供了友好的开发体验,同时让生成的代码更加高效、可靠,可维护。

Form TagHelper

直接举例:

<form asp-controller="Demo" asp-action="Register" method="post">

form>

生成的HTML:

<form method="post" action="/Demo/Register">

  <input name="__RequestVerificationToken" type="hidden" value="" />
 form>

MVC 运行时会根据 Form Tag Helper 的属性 asp-controller 和 asp-action 生成 action的属性值。

命名路由

通过asp-route可以让下面的表单使用路由规则中name为register的路由。

<form asp-route="register" method="post">
    
form>

生成的HTML:

<form asp-controller="Account" asp-action="Login"
  method="post" class="form-horizontal" role="form">
  
form>

Input TagHelper

作用:

  1. 为 asp-for 属性中指定的表达式名称生成 id 和 name 属性。

  2. 基于模型类型和应用在模型属性上的 Tpye 特性来设置 HTML type 的属性值。

  3. 如果 HTML type 属性已被指定,则不会覆盖它。

  4. 根据应用在模型属性上的 验证 特性生成 HTML5 验证属性。

上面第2条说到TagHelper基于 .NET 类型和特性来设置 HTML type 属性。以下是常见的 .NET 类型和特性生成出的 HTML 类型:

.Net类型生成的HTML类型:

.Net类型Input类型
Bool type=”checkbox”
String type=”text”
DateTime type=”datetime”
Byte type=”number”
Int type=”number”
Single, Double type=”number”

.Net特性生成的HTML类型:

AttributeInput Type
[EmailAddress] type=”email”
[Url] type=”url”
[HiddenInput] type=”hidden”
[Phone] type=”tel”
[DataType(DataType.Password)] type=”password”
[DataType(DataType.Date)] type=”date”
[DataType(DataType.Time)] type=”time”

例子:

public class RegisterViewModel
{
    [Required]
    [EmailAddress]
    [Display(Name = "Email Address")]
    public string Email { get; set; }

    [Required]
    [DataType(DataType.Password)]
    public string Password { get; set; }
}
@model RegisterViewModel

<form asp-controller="Demo" asp-action="RegisterInput" method="post">
    Email:  <input asp-for="Email" /> <br />
    Password: <input asp-for="Password" /><br />
    <button type="submit">Registerbutton>
form>

上述代码生成如下的 HTML :

<form method="post" action="/Demo/RegisterInput">
    Email:
    <input type="email" data-val="true"
           data-val-email="The Email Address field is not a valid e-mail address."
           data-val-required="The Email Address field is required."
           id="Email" name="Email" value="" /> <br>
    Password:
    <input type="password" data-val="true"
           data-val-required="The Password field is required."
           id="Password" name="Password" /><br>
    <button type="submit">Registerbutton>
  <input name="__RequestVerificationToken" type="hidden" value="" />
form>

asp-for 属性值是一个 ModelExpression 同时也是 lambda 表达式右边的部分。因此,不需要使用 Model 前缀。

定位子属性

asp-for可以通过视图模型的属性路径定位到子属性。

类代码:

//类A
public class AddressViewModel
 {
     public string AddressLine { get; set; }
 }
//类B中嵌套了类A
 public class RegisterAddressViewModel
 {
     public string Email { get; set; }

     [DataType(DataType.Password)]
     public string Password { get; set; }

     public AddressViewModel Address { get; set; }
 }

视图代码:

@model RegisterAddressViewModel

<form asp-controller="Demo" asp-action="RegisterAddress" method="post">
    Email:  <input asp-for="Email" /> <br />
    Password: <input asp-for="Password" /><br />
    Address: <input asp-for="Address.AddressLine" /><br />
    <button type="submit">Registerbutton>
form>

asp-for是不需要model前缀的,所以直接可以与model中的email等属性绑定。

对于子属性AddressLine,我们可以通过Address.AddressLine来绑定。

TagHelper验证

-validation-for="Email">>

="field-validation-valid"
  data-valmsg-for="Email"
  data-valmsg-replace="true">
>

通常在模型属性相同的 Input Tag Helper后面使用 Validation Message Tag Helper 。这样可以在发生验证错误的 input 旁边显示错误信息。

HTML Helper 替代选项: Html.ValidationMessageFor()

Select TagHelper

Select TagHelper 的 asp-for 为 select 元素指定模型的属性名称,而 asp-items 则指定 option 元素。

类代码:

public class CountryViewModel
{
    public string Country { get; set; }

    public List Countries { get; } = new List
    {
        new SelectListItem { Value = "MX", Text = "Mexico" },
         new SelectListItem { Value = "CA", Text = "Canada" },
         new SelectListItem { Value = "US", Text = "USA"  },
    };
}

public IActionResult Index()
{
    var model = new CountryViewModel();
    model.Country = "CA";
    return View(model);
}

index视图:

@model CountryViewModel

<form asp-controller="Home" asp-action="Index" method="post">
    <select asp-for="Country" asp-items="Model.Countries">select> 
    <br /><button type="submit">Registerbutton>
form>

生成Html:

method="post" action="/">
"__RequestVerificationToken" type="hidden" value="" />

上面asp-for指定的模型类型是单值类型,但如果指定的模型换成一个 IEnumerable 类型, Select Tag Helper 将会在HTML中自动生成 multiple = “multiple”。

注意:只要asp-for 是一个特例,不需要 Model 前缀。

选项分组

当选项分组时,会生成 HTML < optgroup > 元素:

public class CountryViewModelGroup
 {
     public CountryViewModelGroup()
     {
        var AmericaGroup = new SelectListGroup { Name = "America" };
        var EuropeGroup = new SelectListGroup { Name = "Europe" };
        public string Country { get; set; }

        public List Countries { get; } = new List
         {            
             new SelectListItem
             {
                 Value = "CAN",
                 Text = "Canada",
                 Group = AmericaGroup
             },
             new SelectListItem
             {
                 Value = "US",
                 Text = "USA",
                 Group = AmericaGroup
             },
             new SelectListItem
             {
                 Value = "FR",
                 Text = "France",
                 Group = EuropeGroup
             },
             new SelectListItem
             {
                 Value = "ES",
                 Text = "Spain",
                 Group = EuropeGroup
             },            
       };
     }
 }

其余操作与上面Select Tag Helper类似。。。

Select TagHelper的枚举绑定

public enum CountryEnum
{
    Mexico,
    [Display(Name = "United States of America")]
    USA,
    Canada,
    France,
    Germany,
    Spain
}

public class CountryEnumViewModel
 {
     public CountryEnum EnumCountry { get; set; }
 }

视图:

@model CountryEnumViewModel

<form asp-controller="Home" asp-action="IndexEnum" method="post">
    <select asp-for="EnumCountry" 
            asp-items="Html.GetEnumSelectList()"> >
    select> 
    <br /><button type="submit">Registerbutton>
form>

生成HTML:

method="post" action="/Home/IndexEnum">
"__RequestVerificationToken" type="hidden" value="" />

Html Helper与 Input Tag Helper 功能的异同

  1. Html.TextBox、Html.TextBoxFor、Html.Editor 和 Html.EditorFor 有着与 Input Tag Helper 重复的功能。

  2. Input Tag Helper 会自动设置 type 属性,而Html.TextBox 和 Html.TextBoxFor 则不会。

  3. Html.Editor 和 Html.EditorFor 会处理集合、复杂对象以及模版,而Input Tag Helper 则不会。

  4. Input Tag Helper 、Html.EditorFor 和 Html.TextBoxFor 是强类型的,但是Html.TextBox 和 Html.Editor 则不是。

  5. HTML Helper 的Html.TextAreaFor、Html.LabelFor 与Textarea Tag Helper、 Label Tag Helper 类似。

  6. Tag Helper和 HTML Helpers 相比,生成的标记干净得多而且更容易阅读,编辑和维护。

自定义Tag

创建类继承自TagHelper可以让我们扩展tagHelper的功能:

<email>Supportemail>
  • 1
//[HtmlTargetElement(Attributes = "email")]
public class EmailTagHelper : TagHelper
{
    private const string EmailDomain = "contoso.com";

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        output.TagName = "a";    // Replaces  with  tag

        var address = MailTo + "@" + EmailDomain;
        output.Attributes.SetAttribute("href", "mailto:" + address);
        output.Content.SetContent(address);
    }
}

Description:

  1. Tag helper 使用以目标元素名作为根类名,在这个例子中, EmailTagHelper 的根名称是 email ,因此 TagName的默认值就是email。

  2. 重写 Process 方法可以控制 Tag Helper 在执行过程中的行为。 TagHelper 类同样提供了相同参数的异步版本(ProcessAsync)。

  3. 类名后缀TagHelper是非必需的,但它被认为是最佳惯例约定。

  4. 为使自定义的TagHelper在Razor中可用,需要在Views/_ViewImports.cshtml 文件中通过addTagHelper指令添加包含自定义TagHelper的命名空间。

  5. [HtmlTargetElement] 属性传递一个属性参数,指定为任何 HTML 元素包含名为 “bold” 的 HTML 属性。例如:同时使用[HtmlTargetElement(“email”)]和[HtmlTargetElement(Attributes = “email”)],bold 标签和bold 属性都会被匹配。

//异步Process
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
    output.TagName = "a";                                 // Replaces  with  tag
    var content = await output.GetChildContentAsync();
    var target = content.GetContent() + "@" + EmailDomain;
    output.Attributes.SetAttribute("href", "mailto:" + target);
    output.Content.SetContent(target);
}