TagHelper又是一個新的名詞,它替代了自之前MVC版本的HtmlHelper,專注於在cshmlt中輔助生成html標記。
通過使用自定義的TagHelper可以提供自定義的Html屬性或元素,借助服務端強大的編程API,使得cshtml的頁面標記功能更加強大。
利用自定義標記賦予元素功能或添加屬性的方式,跟Angular有點類似。
在MVC Core中內置的很多asp-XXX開頭的TagHelper,后續再介紹,這里重點看看如何定義自己的TagHelper。
我們通過定義一個簡單的TagHelper來描述他的基本用法:
項目准備
還是基於ASP.NET MVC Core Starter Kit的項目模板創建一個示例項目,具體怎樣用請參考鏈接中的介紹。
1.這個TagHelper的目的是提供一個設置button樣色的自定義屬性標記,有這個標記的html元素將自動設置對應的css樣式。
<button type="submit" bs-button-color="danger">Add</button>
這里定義的自定義屬性是bs-button-color,我們預期生成的html是
<button type="submit" class="btn btn-danger">Add</button>
接下來創建TagHelper類,新建一個TagHelpers目錄,新建一個ButtonTagHelper類,如下
public class ButtonTagHelper : TagHelper { public string BsButtonColor { get; set; } public override void Process(TagHelperContext context, TagHelperOutput output) { output.Attributes.SetAttribute("class", $"btn btn-{BsButtonColor}"); } }
這個短小的類,根據程序員的思維可以推導出大概的意思
a.BsButtonColor這個屬性匹配的是bs-button-color這個屬性標記,在運行時會將html屬性轉化成C#對象的屬性
b.然后BsButtonColor的值通過html提供,然后在Process中使用
c.Process方法設置目標元素的class
d.其中TagHelperContext和TagHelperOutput提供了適用的API,拯救了程序員,里面的屬性或者方法夠我們改變世界了。
當然這樣做的話,會讓人產生疑問,那豈不是每個元素都要去匹配一下,沒錯這是默認的行為,后面會提到如何縮小查找范圍。
對於這樣的功能,如果使用老版本的HtmlHelper實現,那么會看起來不那么Html,比如上述的功能用HtmlHelper的實現方式類似如下方式
@Html.TextBoxFor(m => m.Population, new { @class = "form-control" } )
那么這個寫法對於前端開發人員就不那么友好了,畢竟別人不同什么是@Html.TextBoxFor,bs-button-color這種方式更加直接,對html的入侵從視覺上來看更加的友好。
2 注冊TagHelper
光定義還不行,還得注冊讓MVC知道這個自定義的TagHelper。
打開_ViewImports.cshtml,改成如下內容
@using CustomTagHelper.Models
@addTagHelper CustomTagHelper.TagHelpers.*, CustomTagHelper
其中第二行尤為重要,其目的是說明將我們定義的TagHelper添加注冊到頁面中,這樣頁面就能識match到。
注冊完之后就能調用使用了,我們把自定義的TagHelper應用到Home/Create.cshtml的Add按鈕
<button type="submit" bs-button-color="danger">Add</button>
運行之后效果,查看html可以得知已經生效
3 設置TagHelper的應用范圍
剛才我們提到在匹配TagHelper的時候是使用元素類型去匹配,比如我們這里的ButtonTagHelper,會匹配所有的buttton。但實際上這不是我們需要的,我們只希望出現了自定義html標記屬性的元素才應用這個TagHelper。
MVC Core為我們提供了HtmlTargetElement屬性標記類解決這個問題,讓TagHelper的應用更加的精准。
我們更新ButtonTagHelper,加入HtmlTargetElement屬性
[HtmlTargetElement("button", Attributes = "bs-button-color", ParentTag = "form")] public class ButtonTagHelper : TagHelper { public string BsButtonColor { get; set; } public override void Process(TagHelperContext context, TagHelperOutput output) { output.Attributes.SetAttribute("class", $"btn btn-{BsButtonColor}"); } }
看看HtmlTargetElement的定義,也是一目了然
1 第一個參數是tag類型
2 Attributes定義用於選擇匹配應用元素的屬性
3 ParentTag,設置必須是某個html的子元素才設置
當然有了HtmlTargetElement做護航,我們除了可以縮小范圍,當然也可以用它來擴大影響范圍。
比如我們把第一個tag參數去掉,那么就是應用到所有的元素類型(當然也要滿足Attributes和ParentTag條件)
然后把tag參數去掉之后,發現范圍太大不好管控,萬一使用者不知道這范圍定義,那么就會導致樣式錯誤,並且這種bug不好跟,一旦發生也是個坑。
所以既要支持多種tag,又不能污染太多,那么就再apply一個HtmlTargetElement屬性,比如如下
[HtmlTargetElement("button", Attributes = "bs-button-color", ParentTag = "form")] [HtmlTargetElement("a", Attributes = "bs-button-color", ParentTag = "form")] public class ButtonTagHelper : TagHelper { public string BsButtonColor { get; set; } public override void Process(TagHelperContext context, TagHelperOutput output) { output.Attributes.SetAttribute("class", $"btn btn-{BsButtonColor}"); } }
這里用了兩個HtmlTargetElement,指明了只有button和a元素可以應用這個tagHelper,后續哪個人復制粘貼到了其他tag也不會受影響。
示例代碼
https://github.com/shenba2014/AspDotNetCoreMvcExamples/tree/master/CustomTagHelper
先寫到這,下一篇將介紹一些稍微高級一點用法。