本篇對上篇的代碼進行重構。在 SAP Fiori 中 app
并不是通過 index.html
啟動的,而是通過 Component
啟動袍嬉,因為 SAP Launchpad 包含多個 app。所以我們學習 OpenUI5 也應該熟悉這種模式。Component
是 OpenUI5 的一種組織代碼結構的方式音诈。
第一次重構幻碱,代碼的項目文件結構如下:
在 Component 中編寫啟動代碼
我們先來看 Component.js
文件的內容:
sap.ui.define([
"sap/ui/core/UIComponent",
"sap/ui/model/json/JSONModel"
],
function(UIComponent, JSONModel){
return UIComponent.extend("webapp.Component", {
createContent: function() {
UIComponent.prototype.createContent.apply(this, arguments);
// load application data
var oModel = new sap.ui.model.json.JSONModel();
oModel.loadData("webapp/service/data.json");
this.setModel(oModel);
// app view(root view)
var oAppView = sap.ui.view("appView", {
type: sap.ui.core.mvc.ViewType.XML,
viewName: "webapp.view.App"
})
oApp = oAppView.byId("app");
return oAppView;
}
});
}
);
代碼說明:
Component.js
這個文件名不能更改,但位置可以設定细溅。在Component.js
文件中褥傍,webapp.Component
類從sap.ui.core.UIComponent
類擴展,并且改寫了createContent
方法喇聊。接下來的代碼在之前的項目代碼
index.html
中常見恍风,完成加載 Application data,設置webapp.component
這個組件的 Model:
// load application data
var oModel = new sap.ui.model.json.JSONModel();
oModel.loadData("webapp/service/data.json");
this.setModel(oModel);
- 定義一個 Root View誓篱,或者叫做 Application View:
var oAppView = sap.ui.view("appView", {
type: sap.ui.core.mvc.ViewType.XML,
viewName: "webapp.view.App"
})
- 定義一個全局變量
oApp
:
oApp = oAppView.byId("app");
return oAppView;
之前代碼中朋贬, oApp 通過創(chuàng)建 new sap.m.App()
對象實例來實現,本次的示例代碼把它放在 App View 中進行申明燕鸽,一會我們再來看 App View 的代碼兄世。由于在 App View 中申明 app,所以在這里通過oAppView.byId("app")
來獲取全局的 Application 對象啊研。
簡化 index.html
重構后 sap.m.App
在 App View 中聲明御滩,Application Data 和 Root View 的代碼移到 Component.js
文件中,所以 index.html
中的代碼大大減少党远,只需要定義一個 sap.ui.core.ComponentContainer
對象削解,在 ComponentContainer
中包括剛剛定義的 Component
對象。index.html
代碼如下:
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv='Content-Type' content='text/html;charset=UTF-8'/>
<script src="resources/sap-ui-core.js"
id="sap-ui-bootstrap"
data-sap-ui-libs="sap.m"
data-sap-ui-preload="async"
data-sap-ui-xx-bindingSyntax="complex"
data-sap-ui-resourceroots = '{"webapp": "./webapp/"}'
data-sap-ui-theme="sap_bluecrystal">
</script>
<script>
var oApp;
sap.ui.getCore().attachInit(function(){
sap.ui.require([
"sap/ui/core/ComponentContainer",
"webapp/Component"
],
function(ComponentContainer, Component){
new ComponentContainer({
height: "100%",
component: new Component({
id: "mvcAppComponent"
})
}).placeAt("content");
}
);
});
</script>
</head>
<body class="sapUiBody" role="application">
<div id="content" class="sapUiResponsiveMargin"></div>
</body>
</html>
ComponentContainer
實例化的 component
參數指定容器所包含的 Component
沟娱,也可也使用 name
參數氛驮,name
根據文件的相對位置來指定所包含的 Component
對象。比如:name: "webapp"济似,
index.html` 中
data-sap-ui-resourceroots = '{"webapp": "./webapp/"}
指定 webapp
為當前文件夾下的 webapp 文件夾矫废,OpenUI5 就在這個文件夾下查找 Component.js
文件。
App view 內嵌 Master View 和 Detail View
之前是在 index.html
中實例化 Master View 和 Detail View砰蠢,并且將 View 包含在 app 的 pages 中蓖扑。代碼模式如下:
var masterView = sap.ui.xmlview("masterView", {...});
var detailView= sap.ui.xmlview("detailView", {...});
現在變?yōu)?Master View 和 Detail View 在 App.view.xml
文件中申明:
<core:View xmlns:core="sap.ui.core"
xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m"
xmlns:html="http://www.w3.org/1999/xhtml">
<App id="app">
<pages>
<mvc:XMLView id="masterView" viewName="webapp.view.Master" />
<mvc:XMLView id="detailView" viewName="webapp.view.Detail" />
</pages>
</App>
</core:View>
這種 View 中內嵌其它 View ,對后面通過代碼獲取 View 的 id 有影響台舱,OpenUI5 在View 的 id 前自動加上父 View 的 id律杠。比如 Master View 的id變成appView--masterView
,Detail View 的 id 變?yōu)?appView--detailView
竞惋。appView
是 在 Component 中定義Root View時指定的 id柜去。在 Controller 中根據 View 的 id 導航的時候,需要用到這些 id拆宛。
Master Controller 和 Detail Controller 的代碼重構
Master View 和 Detail View 的代碼沒有變化嗓奢,Detail Controller 的代碼也沒有變化。Master Controller 因為需要能從 Master View 跳轉到 Detail View浑厚,并且在跳轉的時候用到 View 的 id蔓罚,所以代碼中 pageId
的代碼有變化:
sap.ui.define([
"sap/ui/core/mvc/Controller"
],
function(Controller){
"use strict";
return Controller.extend("webapp.controller.Master", {
onListPress: function(oEvent){
// 跳轉到detail view
var sPageId = oApp.getPages()[1].getId();
oApp.to(sPageId);
// 設置detail page的bindingContext
var oContext = oEvent.getSource().getBindingContext();
var oDetailPage = oApp.getPage(sPageId);
oDetailPage.setBindingContext(oContext);
}
});
}
);
我們使用相對引用的方式椿肩,getPages()
獲取 app 的頁面,然后通過oApp.getPages()[1].getId()
獲取 Detail Page的 id 豺谈。
在 Component 中實現相關配置
很多參數都可以配置在 Component 中郑象,我們將 Root View 和 Service URL 配置在 Component 的 metadata
中。metadata 也可以放到專門的配置文件中茬末, 這個配置 OpenUI5 叫 Application descriptor厂榛。
sap.ui.define([
"sap/ui/core/UIComponent",
"sap/ui/model/json/JSONModel"
],
function(UIComponent, JSONModel){
return UIComponent.extend("webapp.Component", {
// meta-data
metadata: {
"rootView": "webapp.view.App",
"config": {
"serviceUrl": "webapp/service/data.json"
}
},
createContent: function() {
// application data
var oModel = new JSONModel(this.getMetadata().getConfig().serviceUrl);
this.setModel(oModel);
// root view
var oRootView = UIComponent.prototype.createContent.apply(this, arguments);
// application
oApp = oRootView.byId("app");
return oRootView;
}
});
}
);
代碼說明:
- Component metadata 配置部分的
rootView
,表示程序啟動時的第一個View丽惭。代碼中使用下面的語句獲取击奶。
var oRootView = UIComponent.prototype.createContent.apply(this, arguments);
- json 數據在 metadata 配置的 config->serviceUrl 中,然后代碼中使用下面的語句獲仍鹛汀:
var oModel = new JSONModel(this.getMetadata().getConfig().serviceUrl);
index.html 添加 Shell 組件
為了更加美觀柜砾,一般 OpenUI5 的 App 都是放置在sap.m.Shell
中,這樣换衬,頁面兩邊都有預留空間痰驱,App 位于中間,類似一個信封瞳浦。不錯担映,OpenUI5 就是將有 Shell 的頁面叫 letterboxing - 信封。
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv='Content-Type' content='text/html;charset=UTF-8'/>
<script src="resources/sap-ui-core.js"
id="sap-ui-bootstrap"
data-sap-ui-libs="sap.m"
data-sap-ui-preload="async"
data-sap-ui-xx-bindingSyntax="complex"
data-sap-ui-resourceroots = '{"webapp": "./webapp/"}'
data-sap-ui-theme="sap_bluecrystal">
</script>
<script>
var oApp;
sap.ui.getCore().attachInit(function(){
sap.ui.require([
"sap/m/Shell",
"sap/ui/core/ComponentContainer",
"webapp/Component"
],
function(Shell, ComponentContainer, Component){
new Shell({
app: new ComponentContainer({
height: "100%",
component: new Component({
id: "mvcAppComponent"
})
})
}).placeAt("content");
}
);
});
</script>
</head>
<body class="sapUiBody" role="application">
<div id="content" class="sapUiResponsiveMargin"></div>
</body>
</html>
頁面效果: