1. 背景
经过一系列的练习,相信大家对于SAPUI5的应用程序已经有了直观的认识,我们在练习中介绍了视图、控制器、模型的概念和用法。在本篇博客中,让我们回顾总结下这些知识点,更深入地理解SAPUI5的MVC架构。
首先,让我们看下SAPUI5的整体架构。
Device层:展示了SAPUI5应用程序的运行设备,SAPUI5应用程序可以在任何设备(手机、平板电脑或台式电脑)的浏览器中运行。
Client/Browser层:展示了SAPUI5的MVC架构,通过“模型-视图-控制器(Model - View - Controller, MVC)”概念将信息的表示与用户交互分离开来。
Resource Hander/Gateway Server层:展示了资源的加载方式,以及应用数据的访问方式。SAPUI5库是从Server加载的,在访问应用程序业务数据,是通过SAP网关(Gateway)或SAP Cloud平台使用OData模型。
接下来,让我们更详细地介绍下Client/Browser层。
2. MVC
2.1 交互关系
MVC(Model-View-Controller)架构是一种设计模式,用于分离应用程序的不同部分,以提高代码的可维护性和可扩展性。MVC 模式将应用程序分为三部分:模型(Model)、视图(View)和控制器(Controller)。
- 模型Model:负责保存应用数据,以及提供读取、设置和更新数据的一系列方法
- 视图View:负责定义和渲染UI
- 控制器Controller:通过修改视图和模型来响应视图事件和用户交互,控制器将视图逻辑与模型逻辑分离
控制器与模型和视图的关系:
- 控制器可以直接修改模型中的数据,它可以通过注册函数的方式,监测模型的变化;
- 控制器可以直接修改视图以及视图上面的元素,通过事件处理程序(event handler),控制器可以响应视图上面的事件。
模型和视图的关系:
- 模型上保存的数据,可以通过"数据绑定"的方式关联到视图上,视图可以读取或编辑模型上的数据(通过数据的实时绑定,不需要将模型上的数据复制到视图上)
2.2 构建要素
让我们拆解一下一个SAPUI5的应用程序,然后分析其构建的元素。
通过上面的拆解图,可以看到:
- 视图,是由最基本的SAPUI5控件构成(例如如表,按钮,输入框,复选框);
- 每一个视图,都会有一个对应的控制器,用于负责UI相关的业务逻辑;
- 模型是负责数据的操作,包括客户端和服务器端的数据;
- 而组件,是用于应用程序的描述和封装,使得应用程序可以运行在不同的组件容器中。
2.1 模型(Model)
模型代表应用程序的数据和业务逻辑,它负责数据的获取、存储和处理。
在SAPUI5中,负责数据模型绑定的API是
sap.ui.model
。它可以处理JSON、XML 或 OData等格式的数据。模型支持的绑定模式有单向
、双向
和一次性
,绑定模式可以由应用程序指定或更改。
通常情况下,我们在JavaScript文件中,会首先加载模型文件中的数据,然后通过视图对象提供的
setModel()
方法,将模型数据绑定到视图对象上。在视图上,可以通过绑定表达式{...},例如,{/recipient/name}, {i18n>helloMessage}
获取模型上面的数据。
2.1.1 JSONModel(JSON模型)
SAPUI5中的JSON Model是一个客户端模型,可以用于在SAPUI5应用程序中处理和操作JSON数据。SAPUI5提供了绑定控件数据到JSON对象的机制,使得当JSON数据改变时,UI控件也会自动更新。
代码示例:
// 创建一个JSON Model实例
var oModel = new sap.ui.model.json.JSONModel();
// 设置JSON数据到模型中
var oData = {
"employees": [
{ "firstName": "John", "lastName": "Doe" },
{ "firstName": "Anna", "lastName": "Smith" },
{ "firstName": "Peter", "lastName": "Jones" }
]
};
oModel.setData(oData);
// 将模型绑定到视图
this.getView().setModel(oModel);
在视图文件中,使用以下方式绑定数据到控件:
<List items="{/employees}">
<items>
<ObjectListItem title="{firstName}" intro="{lastName}" />
</items>
</List>
在上述示例中,我们首先创建了一个JSON Model实例,然后设置了一些JSON数据到模型中。然后,我们将模型绑定到视图。在视图中,我们使用绑定语法将数据绑定到一个列表控件。当JSON数据改变时,列表控件会自动更新。
当然JSON模型中的数据,是可以存储在单独的JSON文件中的,当需要处理模型数据时,可以从JSON文件中加载,如下例:
var oModel = new sap.ui.model.json.JSONModel();
oModel.loadData("mydata.json");
sap.ui.getCore().setModel(oModel);
2.1.2 ResourceModel资源模型
ResourceModel资源模型用于处理i18n资源束,用于实现应用程序的国际化。
代码示例:
var oModel = new sap.ui.model.resource.ResourceModel({
bundleName: "myapp.i18n.i18n"
});
sap.ui.getCore().setModel(oModel, "i18n");
2.1.3 XMLModel
XMLModel是一个客户端模型,用于处理XML格式的数据。它可以用于存储和处理来自服务器的XML数据。
代码示例:
var oModel = new sap.ui.model.xml.XMLModel();
oModel.loadData("mydata.xml");
sap.ui.getCore().setModel(oModel);
2.1.4 ODataModel
ODataModel是一个服务器模型,用于处理OData服务。它可以用于与OData服务进行交互。
代码示例:
var oModel = new sap.ui.model.odata.v2.ODataModel("/my/service/url/");
sap.ui.getCore().setModel(oModel);
2.2 视图(View)
在SAPUI5中,视图/View是一个用于定义用户界面的组件。负责展示数据并接收用户的输入。视图通常与一个或多个控制器关联,控制器负责处理用户的操作并更新模型的数据。
视图可以包含各种UI元素,如按钮、表格、图表等。
SAPUI5 支持多种视图类型(XML、HTML、JavaScript)。在使用 UI5 时,官方建议使用 XML视图,因为这样的代码可读性高,并会迫使我们将视图逻辑与控制器逻辑分开。
在创建视图文件时,要注意:
- 视图名称大写 (例如,
App.view.xml
) - 所有视图都存储在
view
文件夹中 - XML视图的名称总是以
*.view.xml
结尾 - 默认的XML命名空间是
sap.m
- 其他XML命名空间使用SAP命名空间的最后一部分作为别名(例如,
sap.ui.core.mvc
的别名为mvc
)
以下是一个使用XML定义的视图的示例:
<mvc:View controllerName="sap.ui.demo.walkthrough.controller.App" xmlns:mvc="sap.ui.core.mvc" displayBlock="true" xmlns="sap.m">
<App id="app">
<pages>
<Page title="{i18n>title}">
<content>
<Button text="{i18n>showHelloButtonText}" press="onShowHello" id="helloButton" />
</content>
</Page>
</pages>
</App>
</mvc:View>
在这个示例中,视图包含一个App组件,App组件包含一个Page组件,Page组件包含一个Button组件。Button组件的文本和按下事件由控制器处理。
2.3 控制器(Controller)
在SAPUI5中,控制器负责处理用户交互,处理业务逻辑,以及更新模型和视图。
控制器是一个JavaScript文件,它包含了一个特定视图的事件处理函数和业务逻辑。
- 每个视图都有一个与之关联的控制器。
- 控制器可以访问其关联的视图,以及视图中的控件。
- 控制器还可以访问模型,以便获取和修改数据。
在SAPUI5中,控制器的创建和使用通常遵循以下步骤:
- 在
webapp/controller
目录下创建一个新的JavaScript文件,例如MyController.js。 - 在新的JavaScript文件中,定义一个新的SAPUI5控制器,这个控制器应该继承自
sap.ui.core.mvc.Controller
并作为返回对象,返回的控制器对象包含了控制器逻辑的实现。 - 在控制器中,定义事件处理函数和业务逻辑。这些函数可以通过
this.getView()
访问关联的视图,以及视图中的控件。 - 在视图中,使用
controllerName
属性指定关联的控制器。
在创建控制器文件时,要注意:
- 控制器名称大写 (例如,App.controller.js)
- 控制器与相关视图的
名称相同
(如果存在1:1关系) - 事件处理程序以
on
为前缀 - 控制器名称总是以
*.controller.js
结尾
以下是一个简单的SAPUI5控制器的示例:
sap.ui.define([
"sap/ui/core/mvc/Controller"
], function (Controller) {
"use strict";
return Controller.extend("my.namespace.MyController", {
onInit: function () {
// 在控制器初始化时执行的代码
},
onButtonPress: function () {
// 处理按钮按下事件的代码
var oView = this.getView();
var oButton = oView.byId("myButton");
oButton.setText("Pressed");
}
});
});
在这个示例中,MyController控制器定义了两个函数:onInit
和onButtonPress
。onInit
函数在控制器初始化时被调用,onButtonPress
函数用于处理按钮按下事件。
控制器的_hook
方法是由框架定义的,并在视图和应用程序的特定状态下调用。
onInit()
: 只调用一次,当视图被实例化时,所有控件已经被创建。我们可以在这里修改视图,获取UI元素的引用,注册事件处理程序或初始化控制器和子组件。onExit()
: 在视图及其控制器被销毁之前调用,用于释放资源和完成操作(或保存草稿)。onAfterRendering()
: 只在视图渲染后调用一次,我们可以执行后渲染操作。onBeforeRendering()
: 每当视图由于UI更改而重新渲染时调用,在第一次初始化步骤期间不会被调用。
2.4 启动应用程序
在MVC框架下,一个SAPUI5应用的启动过程如下:
当用户启动SAPUI5应用程序后:
- SAPUI5框架首先会加载相关所需的资源
- 然后,组件容器加应用程序的组件
- 当组件就绪后,会加载此应用程序的描述符文件,也即
manifest.json
- 根据
manifest.json
中的描述,组件会创建相关的模型对象,例如资源模型i18n
- 然后,组件文件
Component.js
中的init()
函数会被触发。在init()
函数中,通常会完成模型的实例化,并完成数据绑定setModel()
。模型一般会直接绑定在组件上的,因为嵌套的控件会自动地继承父控件的承模型,因此模型的数据在视图上也是可用的。 - 需要注意,在触发组件文件
Component.js
中的init()
函数时,其会先调用其父类sap/ui/core/UIComponent
的init()
函数,以完成Router的创建,以及定义在manifest.json
中rootView
(也即应用程序的根视图)的创建 - 根视图会根据其内部的声明,创建根组件
- 与此同时,组件文件中的
init()
函数会初始化Router - Router就绪后,会去创建其它必要的视图
- 在视图内部,会加载对应的控制器文件
- 在加载过程中,控制器内的
init()
函数也会被相应地触发 - Router会将视图放置于根控件上,此时,在视图上,模型数据都是可用的
- 接下来,会对绑定数据至视图进行评估
- 没有问题的话,会完成数据绑定,也即将模型上面的数据真正绑定在视图上
以上就是整个MVC架构下的程序加载过程。
3. 小结
本文对于SAPUI5的MVC框架进行了回顾和总结,通过本篇文章,将进一步加深前序博客中知识点的理解和认知。