MVC Coe 1.0 的 Tag Helper 下集

  • 436
  • 0

上一篇文章介紹了 MVC Core 1.0 的 tag helper,所以這一篇文章將是上一篇文章的延伸.將從上篇文章中所談的自訂 tag helper 範例再繼續開始.

上篇文章裡,你已經可以看到一個相當基本的 tag helper 範例,上篇文章的內容相信能幫助你建立一些基本的  tag helper.從上一個例子裡,你看到了做一個 <manage-has-password> 是相當簡單的, 基本上我們只要 override Process() 即可,然後在 Process() 裡面依照自己需要的邏輯來制做出輸出的 html 內容即可.在那例子裡,我是用最原始的方法來製造 href 屬性的內容.你可以看到我是用字串組合的方式把 href 屬性內容拼裝出來的,所以在那例子裡,href 的路徑是 hard code 上去的.如下所示:

var href = $"/Manage/{action}";

這樣做並沒有特別不好的地方,只是有點原始的方式來拼湊出 href 的路徑.當你執行這個 web application 時,你在範例網站上註冊了一個帳號後,然後到 /Manage/Index 的畫面上時,你就可以看到 tag helper 為你翻譯出來的 HTML 原始碼如下:

        <dt>Password:</dt>
        <dd>
            <a href="/Manage/ChangePassword">Change</a>
        </dd>

若你按下畫面上的 "Change" 時,你就會被導向到 /Manage/ChangePassword 的畫面上.所以,把路徑用原始的拼裝方法來做也是可以的.但因為 MVC 裡面已經準備了 UrlHelper 物件並且也放在 Dependency Injection 的儲存空間中了,所以若你需要 Url 相關的幫助程式的話,可以把它從 Dependency injection 空間裡面抓出來使用.所以剛剛的簡單例子可以改成如下:

首先,對 ManageHasPasswordTagHelper 製做 constructor 並且將 IUrlHelperFactory 設定為輸入參數

        private readonly IUrlHelperFactory _urlHelperFactory;

        public ManageHasPasswordTagHelper(IUrlHelperFactory urlHelperFactory)
        {
            _urlHelperFactory = urlHelperFactory;
        }

這是 MVC Framework 裡的取得 dependency inejction 裡的物件最簡單的方式.IUrlHelperFactory 是  UrlHelper 的 factory,透過它來幫我們決定我們要使用的是那一種 UrlHelper,因為在這裡我們需要的是跟 View 有關的 UrlHelper.所以,我們得告訴 IUrlHelperFactory 我們現在 View 的相關訊息,因此,需要宣告一個 ViewContext 屬性,這是 MVC 在 rendering view 時會設定的物件,顧名思義就知道這是 view 的內容.有了 IUrlHelperFactory 和 ViewContext 之後,我們就可以得到 UrlHelper,然後再透過 UrlHelper 幫我們組裝出 href 的路徑.全部的程式碼如下:

    public class ManageHasPasswordTagHelper : TagHelper
    {
        private readonly IUrlHelperFactory _urlHelperFactory;

        public ManageHasPasswordTagHelper(IUrlHelperFactory urlHelperFactory)
        {
            _urlHelperFactory = urlHelperFactory;
        }

        [ViewContext]
        public ViewContext ViewContext { get; set; }

        public bool Change { get; set; }
        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            output.TagName = "a";

            string link = Change ? "Change" : "Create";
            output.Content.SetContent(link);

            string action = Change ? "ChangePassword" : "SetPassword";
            //var href = $"/Manage/{action}";

            IUrlHelper urlHelper = _urlHelperFactory.GetUrlHelper(ViewContext);
            string href = urlHelper.Action(action, "Manage");
             
            output.Attributes.SetAttribute("href", href);

            output.PreElement.SetContent("[ ");
            output.PostContent.SetContent(" ]");
        }
    }

IUrlHelper 提供較多的 method 可以幫我們組裝各式各樣的 url 內容,所以這樣做會比我們直接用原始的路徑拼裝方式要來的好些.不過,若你的 href 所需的路徑內容很單純的話,其實直接拼裝也是可以的.在上面程式碼最後,我在 HTML 輸出的資料上在前面加了一個 [ ,在最後面加了 ] ,所以你在畫面上就會看到 [ Change ] 或 [ Create ] .在這邊特別是用 PreElement 和 PostContent 來做,這樣可以和主要的 output.Content 做一個區別,才不會在組裝文字上搞錯了.

以上這個例子是使用在 <a> element,程式碼所做的事情都是在組合 href 的內容以及 <a> 所要呈現出的連結文字.因此,在 Process() 一開始就可以看到 output.TagName = "a";,但是當你在 /Manage/Index.cshtml 上使用 <manage-has-password> 時,你並不會看到在 Visual Studio 上提供給你有關 <a> 的其他屬性.

從上面你可以看到只有 view-context ,而沒有其他 <a> 的屬性.為了要讓 Visual Studio 認得 <manage-has-password> 其實就是一個 <a> 時,我們只要在程式碼上加上一行宣告.

    [OutputElementHint("a")]
    public class ManageHasPasswordTagHelper : TagHelper
    {

利用 OutputElementHint 來宣告 ManageHasPassword 其實就是一個 <a>,在編譯過程式之後,再回到 index.cshtml 時,你就可以看到 VIsual Studio 為你列出 <a> 的相關屬性了,因為它知道 <manage-has-password> 就是一個 <a>.

希望透過這兩篇簡單的介紹文章能讓你對 MVC 的 tag helper 以及如何製做自己的 tag helper 有幫助.

Hope it helps,