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()
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是一個比較複雜但是非常強大的工具,我們可以在後續接著探討。