定义和使用模块
学习目标
模块化 SAPUI5 应用
模块化
SAPUI5 框架为应用程序模块化提供内置支持。也就是说,应用可以被拆分为更小的部分,而不是定义和加载一大捆 JavaScript 代码,这些部分可以在运行时按需加载。
观看视频,了解此模块化概念的重要特性。
视频:本节含 SAP 官方视频(视频 ID
1_di20fg8z),需在 learning.sap.com 在线观看。
有关详细信息,请参阅 Demo Kit 中的 API Reference 以及下一节中的示例。
模块定义
如前所述,SAPUI5 模块通过调用 sap.ui.define 方法定义。通过 sap.ui.define 完成的实现决定了模块所谓的导出值。该导出值通常是一个 JavaScript 对象,从使用角度表示模块的值。通常,导出值通过一个函数确定。
sap.ui.define 的典型用法是在 JavaScript 文件中对该方法进行一次顶层调用。当首次请求某个模块时,该 JavaScript 文件会被加载并执行,进而执行对 sap.ui.define 的顶层调用。

图 Simple Module Definition 展示了一个简单的模块定义示例。在存储在项目 *webapp* 文件夹中的 *index.js* 文件里,调用了 sap.ui.define 方法。
可以向 sap.ui.define 方法传递一个数组。该依赖项数组中的每个条目都代表当前定义的模块所依赖的另一个模块的名称。所使用的 SAPUI5 模块的名称以及当前定义的模块的名称都由非空的名称段序列组成。各个名称段之间用正斜杠 ('/') 分隔。
示例中定义的模块在其实现中使用了 sap.m.Text 控件。因此它依赖于实现 sap.m.Text 控件的相应模块。该模块名为 sap/m/Text,并被添加到依赖项数组中。
注意
SAPUI5 控件始终以模块的形式实现。模块名称由控件的类名派生而来,方法是将类名中的点 ('.') 替换为正斜杠 ('/')。在 API Reference 中的 Demo Kit 里,你可以在相应控件文档的头部找到属于某个控件的模块名称。
在确定当前定义的模块的导出值之前,会加载依赖项数组中列出的所有模块。为此,每个所需模块的导出值都会作为参数传递给工厂函数,而该工厂函数又会被交给 sap.ui.define 方法。一旦所有所需模块都加载完成,就会调用该工厂函数。工厂函数参数的顺序与依赖项数组中模块的顺序一致。工厂函数参数的名称是任意的。但通常使用模块名称的最后一个名称段作为参数名。
在所示示例中,传递给 sap.ui.define 的工厂函数有一个名为 Text 的参数。该参数用于引用依赖项数组中 sap/m/Text 模块的导出值。如果首次使用示例中定义的模块,则只有当浏览器中 sap/m/Text 模块可用时才会调用工厂函数。在工厂函数的实现中,随后可以通过 Text 参数访问 Text 控件。
通常,工厂函数通过 return 语句返回一个值,例如 JavaScript 对象。该值随后代表模块的导出值。在所示示例中,没有返回任何值。为简单起见,仅通过 Text 控件将文本 Hello World 添加到 UI 区域。
注意
在工厂函数实现中使用的 use strict;
字面量表达式是在 JavaScript 1.8.5 (ECMAScript 5) 中引入的。它指示浏览器在所谓的严格模式下执行代码。严格模式有助于在开发周期的早期发现潜在的编码问题。例如,它意味着确保变量在使用之前已声明。严格模式有助于避免常见的 JavaScript 陷阱,因此是一种值得采用的良好实践。
模块的加载
在图 Asynchronous Loading of Modules 所示的引导脚本中,默认引导文件 sap-ui-core.js 从 resources 文件夹加载。因此,默认情况下 SAPUI5 会相对于该文件夹加载所有模块。这对于作为 SAPUI5 交付内容一部分的模块是可行的。但是,对于开发人员在 SAPUI5 项目中创建的模块,这种方式会失败。

配置选项 resourceroots
使用 resourceroots 配置选项,可以将对应用程序特定模块的请求重定向到相应的 Web 应用。要设置此配置选项,例如可以将属性 data-sap-ui-resourceroots 添加到引导脚本中。该配置选项的值是一个资源位置映射,以相应的模块 Id 前缀作为键。
在所示示例中,模块 Id 前缀 sap.training.exc 被分配给当前文件夹,即包含所示引导脚本所在文件的文件夹。在该示例中,这就是 webapp 文件夹。
上面讨论的模块实现在名为 *index.js* 的文件中,该文件存储在 webapp 文件夹里。使用此处定义的模块 Id 前缀,请求该模块的 Id 如下:
sap/training/exc/index
此处
sap/training/exc
指向
webapp
文件夹,该文件夹中包含文件
index.js
。文件扩展名
.js
未指定,会在加载过程中自动添加。
配置选项 async
对于 sap.ui.core 或 sap.m 等 SAPUI5 库,存在名为 *library-preload.js* 的所谓库预加载文件。这些预加载文件包含相应库的所有模块。
将属性 data-sap-ui-async=true 添加到引导脚本中,可使模块加载器异步加载单个模块以及库预加载文件。
配置选项 onInit
可以在引导脚本中使用属性 data-sap-ui-onInit 来定义初始化后执行的代码。在这种情况下,模块通过前缀 module: 指示。
在所示示例中,上面讨论的 sap/training/exc/index 模块会在框架初始化后(异步)加载并执行。
使用模块
业务场景
在本练习中,你将把在上一练习中实现的、用于创建和放置 Hello World Text UI 元素的逻辑从 HTML 页面移出,放入一个单独的模块中。然后,你将从 *index.html* 页面以声明方式调用该模块。*模板:*Git 仓库:https://github.com/SAP-samples/sapui5-development-learning-journey.git,分支:*sol/2_bootstrapping模型解决方案:*Git 仓库:https://github.com/SAP-samples/sapui5-development-learning-journey.git,分支:sol/3_modules
任务 1:删除 <script> 标签
步骤
确保
*index.html*页面已在编辑器中打开。删除文件中用于创建和放置
Hello WorldText UI 元素的<script>标签。删除以下行:
<script>
var oText = new sap.m.Text({text: "Hello World"});
oText.placeAt("content");
</script>
结果
HTML 页面的 <head> 标签现在应如下所示:

任务 2:实现模块
步骤
在
*webapp*文件夹中创建一个名为*index.js*的新文件。打开项目结构中
*webapp*文件夹的上下文菜单。选择 New File。
在出现的字段中,输入
index.js并按 Enter。
结果
该
index.js
文件已创建并显示在编辑器中。
2. 将以下代码添加到 *index.js* 文件中,以定义一个模块,通过该模块创建 Hello World Text UI 元素并将其放置在 HTML 页面上:
sap.ui.define(["sap/m/Text"], function (Text) {
"use strict";
new Text({ text: "Hello World" }).placeAt("content");
});
结果
*index.js* 文件应实现如下:

任务 3:以声明方式加载模块
步骤
确保
*index.html*页面已在编辑器中打开。将以下属性添加到引导脚本中:
data-sap-ui-async="true"
data-sap-ui-onInit="module:sap/training/exc/index"
data-sap-ui-resourceroots='{"sap.training.exc": "./"}'
注意
添加的配置告知 SAPUI5,sap.training.exc 命名空间中的资源与 index.html 位于同一目录中。该命名空间用于初始加载 index.js 模块。出于性能考虑,SAPUI5 被启用以异步加载模块和库预加载文件。
HTML 页面的
<head>标签现在应如下所示:
通过从 SAP Business Application Studio 启动应用来进行测试运行。
右键单击你的 sapui5-development-learning-journey 项目中的任意子文件夹,然后从出现的上下文菜单中选择 Preview Application。
在出现的对话框中选择名为 start-noflp 的 npm 脚本。
在已打开的应用程序中,检查
sap.m.TextUI 元素的Hello World文本是否显示在 HTML 页面上。