關於TagHelper的那些事情——自定義TagHelper(內嵌TagHelper)

內嵌TagHelper

上一篇文章中提到有時候須要設計一種內嵌的TagHelper,以下:html

<my name="yy" age="35">
   <location country="China" city="Shanghai" district="PuDong"></location>
</my>

location就是一個內嵌的TagHelper,咱們能夠在location裏設置與它相關的Attributes,有時候設置有多層內嵌的TagHelper。那麼怎樣設計出這樣的一個內嵌的TagHelper來呢?其實它和通常的TagHelper沒什麼的區別,你們能夠利用前面咱們介紹的來設計出它的TagHelper類及Attributes。和通常的TagHelper的主要區別是,它和父TagHelper關聯。如何創建這種關聯?這也是這章咱們須要搞清楚的。異步

經過前面章節學習,咱們知道設計的自定義TagHelper類都會繼承於抽象類TagHelper,在這個類中有二個方法:ide

//同步處理
public virtual void Process(TagHelperContext context, TagHelperOutput output);

//異步處理
public virtual Task ProcessAsync(TagHelperContext context, TagHelperOutput output);

通常咱們會根據實際狀況來選擇重載哪一個方法。在TagHelper抽象類中,異步處理是調用同步處理方法。在這兩個方法中參數相同,在這裏詳細介紹第一個參數context。學習

它的類型是TagHelperContext,主要是存放TagHelper相關的信息:this

  1. AllAttributesspa

    TagHelper支持的全部Attribute集合,它是隻讀的。設計

  2. Itemshtm

    類型是IDictionary<object, object>,它是用來和其餘TagHelper進行聯繫樞紐,對象

            /// <summary>
            /// Gets the collection of items used to communicate with other <see cref="ITagHelper"/>s.
            /// </summary>
            /// <remarks>
            /// This <see cref="IDictionary{object, object}"/> is copy-on-write in order to ensure items added to this 
            /// collection are visible only to other <see cref="ITagHelper"/>s targeting child elements.
            /// </remarks>
            public IDictionary<object, object> Items { get; }
    

    從上面的描述能夠看出,這個集合是copy-on-write,也就是說當前TagHelper在Items獲取父TagHelper中的Items信息,也能夠修改,刪除或者添加某一項,可是不會影響到父TagHelper的Items值,同時也會將修改後的Items信息傳給其子TagHelper,子TagHelper的任何修改不會影響到它。blog

在上面咱們提到,設計支持內嵌TagHelper類,關鍵是要創建父子TagHelper的聯繫,看到這裏,我想你們都應該清楚如何創建這種關聯。對了,就是利用context中Items。

主要是在TagHelper的Process方法中作如下事情。  

public virtual void Process(TagHelperContext context, TagHelperOutput output)
{
   // 從context.items獲取父TagHelper信息
   // 處理自身Attributes
   // 將自身信息存放在context.items中
   // 處理本身的子TagHelper
}

更具體的例子以下:

    //定義父TagHelper
    public class PersonTagHelper : TagHelper
    {
        public string Name
        {
            get { return Person.Name; }
            set { Person.Name = value; }
        }
        public int Age
        {
            get { return Person.Age; }
            set { Person.Age = value; }
        }

        private Person _person;
        private Person Person
        {
            get
            {
                return _person ?? (_person = new Person());
            }
            set
            {
                _person = value;
            }
        }
        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            // 保存信息給子TagHelper使用
            context.Items["Parent"] = Person;
            // 執行並獲取子TagHelper內容
            context.GetChildContentAsync();

            // 輸出html元素和啓動腳本
            // 這裏會用到第二個參數output,後面會介紹到如何使用。
        }
    }

    // 定義子TagHelper
    public class LocationTagHelper: TagHelper
    {
        public string Country { get; set; }
        public string City { get; set; }
        public string District { get; set; }

        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            // 獲取來自父TagHelper的信息,並保存到變量裏去
            var parent = context.Items["Parent"] as Person;
            // 處理Attributes的設置
            parent.Location.Country = Country;
            parent.Location.City = City;
            parent.Location.District = District;
            // 保存自身信息,便於子TagHelper使用
            context.Items["Parent"] = parent.Location;
            // 執行並獲取子TagHelper內容
            context.GetChildContentAsync();
        }
    }

    // 定義了父TagHelper中對應的對象實例
   // 你們能夠根據各自需求,決定是否須要定義這樣一個類型
    public class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }

        private Location _location;
        public Location Location
        {
            get { return _location ?? (_location = new Location()); }
        }
    }
 
    // 定義子TagHelper中數據類型
    // 你們能夠根據各自需求,決定是否須要定義這樣一個類型
    public class Location
    {
        public string Country { get; set; }
        public string City { get; set; }
        public string District { get; set; }
    }

對於類Person和Location的定義你們能夠根據具體狀況來決定是否須要。

這個例子只是簡單展現如何利用Items信息來構建父子TagHelper間的聯繫,你們在具體的項目開發中根據實際需求,寫出不同的代碼來,但有一點不變,就是要利用Items。

相關文章
相關標籤/搜索