繼續來學習UI5的MVC模型吧,這次我們來探討視圖與控制器。
1 視圖
在MVC中,視圖用來定義和渲染UI。在UI5中,視圖的類型是可以自定義的,除了以下預定義的四種視圖類型之外,你也可以定制自己的視圖類型。 預定義的四種視圖類型如下:
- XML view
- JSON view
- JS view
- HTML view
如果你想定義自己的視圖類型,可以通過擴展 sap.ui.core.mvc.View
這個基類來實現。
1.1 視圖的加載
視圖可以通過異步(async)或者同步(sync)的方式加載,默認是同步的方式。視圖的工廠函數通過同步的方式請求並傳入視圖定義的源代碼並返回一個視圖的實例。但是這種方式會導致在加載視圖的時候UI界面卡住,而且也有可能會導致視圖在初始化期間一些函數不能夠被正常調用。 所以,為了避免這種情況,可以通過異步(asynchronous)的方式來加載視圖,所有的視圖類型都支持異步的方式。
以下是一個同步加載視圖的例子,視圖實例被創建之后放到id為uiArea的DOM元素中,隨后視圖會被渲染。
var oView = sap.ui.xmlview({ viewName: “sample.view” }); // the instance is available now oView.placeAt(“uiArea”);
以下的代碼片段是一個異步模式加載視圖的例子,請求視圖工廠函數創建視圖實例,但是此時由於這個請求是一個異步的模式,視圖實例還沒有ready,所以我們不能馬上用 placeAt
來把它放到DOM元素中,我們必須等待View.prototype.loaded()執行完畢的 Promise
,在 then()
中才能真正操作已經實例化完畢的視圖。 如果對於 jQuery
的遞延、回調等等異步概念不太了解的,可以閱讀這篇文章1,如果英文不錯的可以直接看jQuery的官方API2。
sap.ui.xmlview({ viewName: “sample.view”, async: true }).loaded().then(function(oView) { // the instance is available in the callback function oView.placeAt(“uiArea”); });
1.2 視圖的實例化
其實前面也已經提到了,UI5通過 sap.ui.view
這個工廠函數來實例化視圖。
這個工廠函數可以接受如下參數:
type
:
類型可以是預定義的JSON
,JS
,XML
, 或者HTML
, 這些類型都被定義成了枚舉類型,所以在引用的時候可以直接用sap.ui.core.mvc.ViewType
下面的這四個類型的大寫字符串就可以,比如sap.ui.core.mvc.ViewType.XML
就是代表XML視圖,當然直接用字符串 "XML" 也是可以的,規范化起見最好還是使用枚舉類型而不是直接使用字符串字面量。viewName
:
視圖的名字,工廠函數通過這個名字去找到視圖的源碼。viewContent
:
僅僅和XML視圖以及JSON視圖相關,如果一個視圖很簡單(比如就一兩個控件),可以通過這個屬性來定義視圖的內容,當viewName
和viewContent
同時定義的話,只有viewName會起作用,而viewContent會被忽略。Controller
:
可以是任意控制器的實例,如果這里給定了控制器,則視圖中定義的控制器會被覆蓋。viewData
:
僅JS視圖可以使用這個屬性,viewData可以用來保存一些用戶自定義的數據,並且在整個視圖及對應的控制器的生命周期中這些數據都是可用的。
1.3 預定義的視圖類型
1.3.1 JS View
定一個JS view文件只需要把文件名命為類似xxx.view.js的形式就可以了,其中xxx就是視圖的名字,在實例化視圖的時候,這個名字就是需要傳給工廠函數的viewName,當然,記得加上命名空間。
我們需要實現以下兩個方法來完成JS視圖的定義:
getControllerName()
:
指定屬於該視圖的控制器,如果該方法沒有實現,或者返回空,則這個視圖就沒有控制器createContent()
:
當對應的控制器被初始化之后,這個方法會被而且僅會被調用一次來初始化UI。
sap.ui.jsview("sap.hcm.Address", { // this View file is called Address.view.js getControllerName: function() { return "sap.hcm.Address"; // the Controller lives in Address.controller.js }, createContent: function(oController) { var oButton = new sap.ui.commons.Button({text:"Hello JS View"}); oButton.attachPress(oController.handleButtonClicked); return oButton; } });
這里要提到一個要注意的地方,就是當我們在JS view中定義一個控件的時候,有時候我們需要同時定義一個id以方便之后引用,這時需要注意的是,我們不能直接給一個字符串字面量,我們通過類的實例方法 View.createId('idstring')
來實現,通過這種方式返回的id會在我們定義的idstring之前加上所在的類實例id作為前綴以保證唯一性。 但是如果是申明式的視圖類型,就無需使用這個createId方法了,視圖解析器會自動來幫我們做這個事情。
1.3.2 XML View
XML view文件以xxx.view.xml作為文件名。一個XML view定義的示例如下:
<mvc:View controllerName="sap.hcm.Address" xmlns="sap.ui.commons" xmlns:mvc="sap.ui.core.mvc"> <Panel> <Image src="http://www.sap.com/global/ui/images/global/sap-logo.png"/> <Button text="Press Me!"/> </Panel> </mvc:View>
XML view中需要注意的一個問題是命名空間,在XML中定義任何一個控件的時候,都需要加上命名空間。
1.3.3 JSON View
JSON view以xxx.view.json作為文件名。一個JSON view定義的示例如下:
{ "Type":"sap.ui.core.mvc.JSONView", "controllerName":"sap.hcm.Address", "content": [{ "Type":"sap.ui.commons.Image", "id":"MyImage", "src":"http://www.sap.com/global/ui/images/global/sap-logo.png" }, { "Type":"sap.ui.commons.Button", "id":"MyButton", "text":"Press Me" }] }
在JSON view中可以使用字符串、布爾值以及null。
1.3.4 HTML View
HTML view就是通過HTML標簽來定義的視圖,文件名類似 xxx.view.html。樣例如下:
<template data-controller-name="example.mvc.test"> Hello <h1>Title</h1> <div>Embedded HTML</div> <div class="test test2 test3" data-sap-ui-type="sap.ui.commons.Panel" id="myPanel"> <div class="test test2 test3" data-sap-ui-type="sap.ui.commons.Button" id="Button1" data-text="Hello World" data-press="doIt"></div> <div data-sap-ui-type="sap.ui.commons.Button" id="Button2" data-text="Hello"></div> <div data-sap-ui-type="sap.ui.core.mvc.HTMLView" id="MyHTMLView" data-view-name="example.mvc.test2"></div> <div data-sap-ui-type="sap.ui.core.mvc.JSView" id="MyJSView" data-view-name="example.mvc.test2"></div> <div data-sap-ui-type="sap.ui.core.mvc.JSONView" id="MyJSONView" data-view-name="example.mvc.test2"></div> <div data-sap-ui-type="sap.ui.core.mvc.XMLView" id="MyXMLView" data-view-name="example.mvc.test2"></div> </div>
所有視圖相關的屬性都可以通過用data-<property name>的方式在tag <template>中定義。
2 控制器
控制器用來定義業務或者頁面的邏輯。控制器文件必須命名為xxx.controller.js。定義一個控制器的樣例如下:
sap.ui.controller("sap.hcm.Address", { // controller logic goes here });
2.1 生命周期 (Lifecyle Hooks)
對於視圖的不同生命周期狀態,在控制器中有對應的鈎子 (Hooks) 可以讓我們對應於不同的狀態實現一些特定的功能。 UI5提供了下面這些Hooks:
onInit()
視圖被實例化時,當所有的控件已經被創建完成的時候被觸發。
可以在視圖顯示之前做一些修改,或者做一些其他的一次性初始化工作。onExit()
當視圖被銷毀的時候被觸發。
一般可以用來釋放資源或者最終確定一些活動的狀態。onAfterRendering()
當視圖被完全渲染的時候被觸發。
此時視圖已經出現在DOM中了,可以用來操作DOM元素,修改一些HTML。onBeforeRendering()
當視圖被重新渲染的時候被調用,注意在視圖第一次渲染的時候是不會被調用的。
3 總結
MVC是UI5的基礎開發模型,不管你有沒有去刻意的了解它,但是只要你開發UI5,你肯定已經在使用它了。我個人覺得M和C應該還是比較容易理解的,按照API去定義或者用系統生成的文件框架基本上都不會有什么問題。 而問題一般都會出現在V,因為UI5里的控件太多,我們不可能掌握所有控件的用法,即使對於一些熟悉的控件,也沒有機會在所有四種預定義的視圖模型中都去實踐一遍用法,所以很多時候,我們不知道一個控件該怎么用。 這個時候,UI5的幫助文檔中的Explorer會是我們的好朋友,里面列了絕大多數常用控件的用法示例。但也有問題,這就是Explorer中基本上所有的視圖都是用的XML類型定義的,所以我們還需要掌握API的閱讀方法,如何轉換成對應於不同視圖的用法,這就需要 多多實踐了。