1. 背景
在 SAPUI5 中,Fragments 是一种轻量级的 UI 组件,类似于视图(Views),但它们没有自己的控制器(Controller)。Fragments 通常用于定义可以在多个视图中重用的 UI 片段,从而提高代码的可重用性和模块化程度。
Fragment技术应用场景如下:
- 代码重用:将常用的 UI 片段(如对话框、表单、工具栏等)定义为 Fragments,以便在多个视图中重用。
- 模块化开发:将复杂视图分解为多个小的、可重用的 Fragments,提高代码的可维护性。
- 动态加载:根据用户操作或其他条件动态加载 Fragments,提高应用程序的灵活性。
注1:由于 Fragments 没有自己的控制器,它们会使用嵌入它们的视图的控制器。
注2: Fragments 是一段独立的 UI 代码,可以用 XML、HTML、JSON 或 JavaScript 编写,在SAPUI5中推荐的方式是使用
XML
。格式要求:以.fragment.xml
结尾,例如:FragmentName.fragment.xml。碎片文件的位置应放在视图view
文件夹下。
2. 示例
假设我们有一个对话框 DialogFragment,需要在多个视图中使用。
2.1 创建 Fragment
DialogFragment.fragment.xml
xml
<core:FragmentDefinition
xmlns="sap.m"
xmlns:core="sap.ui.core">
<Dialog id="myDialog" title="My Dialog">
<content>
<VBox>
<Text text="This is a dialog fragment"/>
<Input placeholder="Enter something"/>
</VBox>
</content>
<buttons>
<Button text="OK" press="onDialogOk"/>
<Button text="Cancel" press="onDialogCancel"/>
</buttons>
</Dialog>
</core:FragmentDefinition>
2.2 在视图中使用 Fragment
MainView.view.xml
xml
<mvc:View
controllerName="myApp.controller.MainView"
xmlns:mvc="sap.ui.core.mvc"
xmlns="sap.m">
<Page>
<content>
<Button text="Open Dialog" press="onOpenDialog"/>
</content>
</Page>
</mvc:View>
MainView.controller.js
js
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/ui/core/Fragment"
], function (Controller, Fragment) {
"use strict";
return Controller.extend("myApp.controller.MainView", {
onOpenDialog: function () {
var oView = this.getView();
// Check if the fragment is already created
if (!this.byId("myDialog")) {
// Load the fragment asynchronously
Fragment.load({
id: oView.getId(),
name: "myApp.view.DialogFragment",
controller: this
}).then(function (oDialog) {
// Connect dialog to the root view of this component (models, lifecycle)
oView.addDependent(oDialog);
oDialog.open();
});
} else {
this.byId("myDialog").open();
}
},
onDialogOk: function () {
this.byId("myDialog").close();
},
onDialogCancel: function () {
this.byId("myDialog").close();
}
});
});
3.练习
在前序练习的基础上,让我们为应用程序增加一个对话框,对话框相对特殊,因为它会在常规应用程序内容的顶部弹出,因此并不属于某个特定视图。
这意味着我们需要在控制器的某个位置,完成对话框的实例化。但由于我们想使用声明的方式创建控件,并希望保持可复用性和灵活性,我们将使用fragment技术来创建一个包含对话框的XML碎片。这样,对话框就可以在应用程序的多个视图中使用。
3.1 创建包含对话框的碎片
让我们在视图文件下,新建HelloDialog.fragment.xml
碎片文件,在此文件中用声明的方式定义对话框<Dialog>
控件。
碎片资源库位于sap.ui.core
的命名空间中,我们在FragmentDefinition
标签内部为它添加了一个xml
命名空间。
定义Fragment的语法与视图类似,但由于片段没有控制器,因此无需定义该属性。
另外,碎片不在应用程序的DOM树中留下任何痕迹,也没有片段本身的控制实例(只有包含的控件)。 它只是一组可重用控件的容器。
HelloDialog.fragment.xml
碎片文件中的代码如下:
xml
<core:FragmentDefinition
xmlns="sap.m"
xmlns:core="sap.ui.core" >
<Dialog
id="helloDialog"
title="Hello {/recipient/name}"
/>
</core:FragmentDefinition>
3.2 在主视图上新增按钮
接下来,让我们在HelloPanel.view.xml
视图中添加了一个新按钮<Button>
来打开对话框,并指定事件处理函数press=".onOpenDialog"
。与此同时,让我们为此按钮控件设置一个id="helloDialogButton"
。
将关键控件的唯一ID设置为helloWorldButton是一个好习惯,这样可以方便识别。如果未指定id属性,则OpenUI5运行时会为控件生成唯一但易变的ID,例如"__button23"。在浏览器中检查应用程序的DOM元素,就可以看到差别。
改动后的HelloPanel.view.xml
视图文件内容如下:
xml
<mvc:View
controllerName="zsapui5.test.controller.HelloPanel"
xmlns="sap.m"
xmlns:mvc="sap.ui.core.mvc"
>
<Panel
headerText="{i18n>helloPanelTitle}"
class="sapUiResponsiveMargin"
width="auto"
>
<content>
<Button
id="helloDialogButton"
text="{i18n>openDialogButtonText}"
press=".onOpenDialog"
class="sapUiSmallMarginEnd"
/>
<Button
text="{i18n>showHelloButtonText}"
press=".onShowHello"
class="myCustomButton"
/>
<Input
value="{/recipient/name}"
valueLiveUpdate="true"
width="60%"
/>
<FormattedText
htmlText="Hello {/recipient/name}"
class="sapUiSmallMargin sapThemeHighligh-asColor myCustomText"
/>
</content>
</Panel>
</mvc:View>
3.3 实现按钮的事件响应
最后,让我们在控制器文件中,实现按钮的事件响应程序。
新增方法onOpenDialog
到HelloPanel.controller.js
中。如果片段中的对话框尚不存在,通过调用控制器模块的loadFragment API
来实例化该片段。该方法返回一个Promise
对象,一旦片段被异步加载完成,该Promise对象会被解析。
改动后的HelloPanel.controller.js
文件内容如下:
js
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/m/MessageToast"
], function (Controller, MessageToast) {
"use strict";
return Controller.extend("zsapui5.test.controller.HelloPanel", {
onShowHello: function () {
// read msg from i18n model
const oBundle = this.getView().getModel("i18n").getResourceBundle();
const sRecipient = this.getView().getModel().getProperty("/recipient/name");
const sMsg = oBundle.getText("helloMsg", [sRecipient]);
// show message
MessageToast.show(sMsg);
},
onOpenDialog: function () {
// create dialog lazily
if (!this.pDialog) {
this.pDialog = this.loadFragment({
name: "zsapui5.test.view.HelloDialog"
});
this.pDialog.then(function (oDialog) {
oDialog.open();
});
}
}
});
});
3.4 增强i18n
别忘记为新增button的描述维护对应的i18n资源文件。
改动后的i18n.properties
文件如下:
js
# App Descriptor
appTitle=Hello World
appDescription=A simple app that explains the most important concepts of SAPUI5
# Hello Panel
showHelloButtonText=Say Hello
helloMsg=Hello {0}
homePageTitle=homePageTitle
helloPanelTitle=PanelTitle
openDialogButtonText=Say Hello With Dialog
3.5 运行程序
运行改动后的程序,我们可以看到新增的Say Hello With Button按钮。点击按钮后,会在弹出的窗口中显示Hello World。
目前的这个应用程序还是有些小问题,可见,弹出窗口是无法关闭的。在下一篇博客中,让我们进一步增强Fragment的回调函数,来实现弹出窗口的关闭。
4. 小结
本文介绍了SAPUI5中对话框和碎片的概念,并通过示例展示了其具体用法。