xmlplus 組件設計系列之七 - 路由(ViewStack)

在瀏覽器端,對路由的理解通常是根據不一樣的 URL 完成頁面的切換。在服務器端,則是根據不一樣的 URL 請求回饋相關的頁面。在本章,咱們廣義的組件路由的定義:根據接收到的不一樣命令,組件對象呈現出不一樣的子級頁面。在這裏將介紹與路由相關的一個組件,即視圖棧 ViewStack。html

視圖棧初步

該組件在《文檔》部分的最後一個章節《延遲實例化》已經出現過了。這裏將對一些細節部分進行解讀。下面再次給出該組件的源碼。html5

// 07-01
ViewStack: { 
    xml: "<div id='viewstack'/>",
    fun: function (sys, items, opts) {
        var args, children = this.children(),
            table = children.call("hide").hash(),
            ptr = table[opts.index] || children[0];
        if (ptr) ptr = ptr.trigger("show").show();
        this.on("switch", function ( e, to ) {
            table = this.children().hash();
            if ( !table[to] || table[to] == ptr ) return;
            e.stopPropagation();
            args = [].slice.call(arguments).slice(2);
            ptr.trigger("hide", [to+''].concat(args)).hide();
            ptr = table[to].trigger("show", [ptr+''].concat(args)).show();
        });
        return Object.defineProperty({}, "selected", { get: function() {return ptr;}});
    }
}

從靜態接口看,該組件容許提供靜態參數 index,該參數是組件 ViewStack 某一兒子組件對象的名稱,它用於指出哪個子級組件會被最早呈現。請看下面的示例。api

// 07-01
Index: {
    xml: `<ViewStack index='bar'>
              <button id='foo'>foo</button>
              <button id='bar'>bar</button>
          </ViewStack>`
}

該示例中,ViewStack 包含一值爲 bar 的屬性 index,代表組件在實例化時,組件對象 bar 會最早呈現。而默認狀況下,該組件的第一個子級組件會做爲初始顯示對象。再從動態接口看,該組件的函數項導出了一個名爲 selected 的只讀屬性,該屬性用於指示當前顯示的子級組件對象。瀏覽器

經過事件切換目標組件對象

對於子級組件對象之間切換,該組件的函數項並未導出相關的接口,而是經過接收 switch 事件來完成切換。請看下面的示例。服務器

// 07-02
Index: {
    xml: `<ViewStack id='index'>
             <button id='foo'>foo</button>
             <button id='bar'>bar</button>
          </ViewStack>`,
    fun: function (sys, items, opts) {
        sys.index.on("click", "*", function(e) {
            var to = this + '' == "foo" ? "bar" : "foo",
                data = "hello, world";
            this.trigger("switch", [to, data]);
        });
        sys.foo.on("show", function (e, prev, data) {
            console.log("previous page is " + prev, "from data is " + data);
        });
        sys.bar.on("hide", function (e, prev, data) {
            console.log("previous page is " + prev, "from data is " + data);
        });
    }
}

對於該示例,當用戶點擊文字時,文字會在 foo 和 bar 之間切換,也即兩個頁面之間切換,切換是經過相應子級對象派發 switch 事件進行的。另外,組件 ViewStack 在切換頁面時,還會對本次顯示的頁面派發事件 show,以及對本次隱藏的頁面派發事件 hide,相關頁面能夠根據須要選擇偵聽與否。而且在偵聽函數中,能夠獲知前一顯示頁面 ID 以及所傳輸的相關數據。app

動態添加與移除子級對象

組件 ViewStack 支持動態添加與移除子級的組件對象,請看下面的一個示例。ide

// 07-03
Index: {
    xml: `<ViewStack id='index'>
             <button id='foo'>foo</button>
          </ViewStack>`,
    fun: function (sys, items, opts) {
        sys.foo.on("click", function () {
            var xml = "<button id='bar'>bar</button>";
            sys.index.append(xml).trigger("switch", "bar");
        });
    }
}

該示例中,當用戶點擊按鈕 foo 應用會動態添加了一個子級組件,而且經過派發事件 switch 將當前顯示的視圖切換爲剛新添加的視圖。函數

優化配置

組件 ViewStack 通常配合組件的延遲實例化功能使用。對於一些比較複雜的組件,這樣有助於加快顯示應用的初始頁面。下面作簡單示範。優化

// 07-04
Index: {
    xml: `<ViewStack id='index'>
             <button id='foo'>foo</button>
             <button id='bar'>bar</button>
          </ViewStack>`,
    map: { defer: "bar" },
    fun: function (sys, items, opts) {
        sys.foo.on("click", function () {
            sys.index.trigger("switch", "bar");
        });
    }
}

此示例中,ViewStack 子級包含三個子組件,其中組件對象 bar 被設置爲須要延遲實例化,只有當視圖切換在組件對象 bar 時,它才真正開始實例化。this

與 HTML5 History API 的配合使用

這裏咱們看看如何讓組件 ViewStack 與 HTML5 History API 的配合使用。下面是一個簡單的例子。

// 07-05
Index: {
    xml: "<ViewStack id='index'>\
             <button id='foo'>foo</button>\
             <button id='bar'>bar</button>\
          </ViewStack>",
    fun: function (sys, items, opts) {
        sys.index.on("show", "button", function (e) { 
            window.history.pushState({name: this + ""}, null, "/" + this);
        });
        window.addEventListener("popstate", function (e) {
            e.state && sys.index.trigger("switch", e.state.name);
        });
        sys.foo.on("click", e => sys.foo.trigger("switch", "bar"));
        sys.bar.on("click", e => sys.foo.trigger("switch", "foo"));
    }
}

該示例的關鍵點在於,當視圖棧組件對象的子級頁面發生變動時,使用函數 pushState 記錄下來;另外須要偵聽瀏覽器的 popstate 事件,當用戶點擊「前進」、「後退」按鈕時,完成相應頁面的切換。這種技術很是適合在單頁應用中完成無刷新跳轉,能夠給用戶帶來很是好的體驗。

相關文章
相關標籤/搜索