1. 程式人生 > >OPEN(SAP) UI5 學習入門系列之二: 最佳實踐練習(下)

OPEN(SAP) UI5 學習入門系列之二: 最佳實踐練習(下)

可以先把程式碼下載到本地並跑起來,這樣可以對這個最佳實踐的程式有一個直觀的瞭解。

頁面導航如下: 
銷售訂單列表(Master) -> 銷售訂單明細(Detail) -> 行專案明細(LineItem),在每個明細頁面都可以返回到上一層。

具體頁面之間的導航是如何實現的呢? 
我們從頁面的入口 index.html 開始

var oView = sap.ui.view({
    id : "app",
    viewName : "ui5.tutorial.bp.view.App",
    type : "JS",
});
//...
oView.placeAt('content'
);

這一段程式碼初始化了一個叫做App的JS view,那我們就來看 App.view.js

// create app
this.app = new sap.m.SplitApp();

// load the master page
var master = sap.ui.xmlview("Master", "ui5.tutorial.bp.view.Master");
master.getController().nav = this.getController();
this.app.addPage(master, true);

// load the empty page
var empty
= sap.ui.xmlview("Empty", "ui5.tutorial.bp.view.Empty"); this.app.addPage(empty, false);

App view中在 createContent 中建立了一個SplitApp,稍微說下SplitApp這個控制元件,當宿主是PC或者平臺的時候這個控制元件預設包含兩個頁面容器,而當宿主是手機的時候又可以只包含一個頁面,所以一般主從結構的頁面可以用這個控制元件。
隨後,分別建立了兩個頁面,一個是Master頁面,另一個頁面是空白頁——作為沒有選中任何Master頁面中的資料時的預設頁面,最後把兩個頁面都加入到了SplitApp中。
到目前為止都是在上一篇中已經做過的,到這裡,頁面已經可以展示了。但是我們今天要研究的是導航,所以接著往下。
SplitApp本身帶有 to()

 這個函式,可以在已經加入其容器的頁面之間導航,但是我們現在的功能稍稍有點複雜,當點選Master頁面的時候,要求導航到詳細頁面, 點選詳細頁面的行專案可以進入到行專案的詳細頁面,對應每個詳細頁面可以返回至上一級頁面,同時可能還需要做一些其他邏輯上的處理,比如判斷和繫結資料,因此我們需要在原有的 to() 上增強一些功能並封裝給其他的控制器使用。

這些功能都集中定義在 App.controller.js 這個控制器中

to : function (pageId, context) {

    var app = this.getView().app;

    // load page on demand
    var master = ("Master" === pageId);
    if (app.getPage(pageId, master) === null) {
        var page = sap.ui.view({
            id : pageId,
            viewName : "ui5.tutorial.bp.view." + pageId,
            type : "XML"
        });
        page.getController().nav = this;
        app.addPage(page, master);
        jQuery.sap.log.info("app controller > loaded page: " + pageId);
    }

    // show the page
    app.to(pageId);

    // set data context on the page
    if (context) {
        var page = app.getPage(pageId);
        page.setBindingContext(context);
    }
},

/**
 * Navigates back to a previous page
 * @param {string} pageId The id of the next page
 */
back : function (pageId) {
    this.getView().app.backToPage(pageId);
}

重新封裝後的 to() 有兩個引數,一個是頁面id,另一個是上下文,當傳入的頁面不存在的時候,系統會首先初始化這個頁面並加入到當前的SplitApp中,隨後直接呼叫SplitApp的 to() 完成導航動作。 最後,如果上下文不為空的話,把這個上下文繫結到新的頁面中,這對於一個新頁面來說是非常有意義的。
back則直接複用SplitApp的 backToPage() 函式。

接下來我們再看其他的頁面如何複用定義在這裡的導航函式的。
我們回過頭來再看 App.view.js , 其中在初始化Master頁面之後,有這麼一條語句 
master.getController().nav = this.getController(); 
這條語句把當前的控制器賦給Master頁面的控制器的nav,這個nav只是用來存放App控制器的一個key,叫什麼名字都行,這樣在Master頁面中就可以通過nav來呼叫App控制器的所有函數了。

同樣的,再回到 App.controller.js 中,看到這條語句 page.getController().nav = this; 也是類似的作用。

在首頁面剛剛初始化時,Detail頁面是沒有載入的,當點選Master頁面中的某個SalesOrder的時候,Master頁面中的 handleListItemPress 被呼叫:

handleListItemPress : function (evt) {
    var context = evt.getSource().getBindingContext();
    this.nav.to("Detail", context);
}

首先獲得被點選的item上繫結的上下文資訊(資料),然後呼叫App的 to() 方法並傳入 Detail 告訴頁面要載入Detail這個頁面,同時把上下文資料傳遞過去, 接下來又回到了 to() , Detail頁面被初始化,繫結上下文資料,載入到SplitApp中,然後導航成為當前顯示頁面。

以上,就完成了這個App的導航,可以看到有些繁瑣,並且需要顯式的初始化子頁面的時候獲得並共享App的控制器,另外,頁面之間的跳轉不會修改URL,無法將某個中間頁面存為bookmark,所以這種方式並不是UI5所推薦的, 但是作為初學者瞭解UI5的頁面導航機制還是非常的直觀,另外對於簡單的應用來說,如果頁面較少也未嘗不可以考慮。
作為稍大型的web應用,UI5在早期的版本中推薦使用EventBus通過Event的傳遞來實現複雜的頁面導航,從1.6開始引入了新的導航機制,就是Routing,可以將頁面之間的導航關係定義在component中,在最新的1.30版本中,導航定義則可以直接寫在App的說明檔案 manifest.jso 中。
導航就介紹到這裡,Component和Routing是一個比較複雜但是非常強大的工具,我們可以在後續接著探討。