写点什么

深入学习 SAP UI5 框架代码系列之三:UI5 控件的渲染器

作者:Jerry Wang
  • 2022 年 9 月 06 日
    四川
  • 本文字数:2033 字

    阅读完需:约 7 分钟

深入学习SAP UI5框架代码系列之三:UI5 控件的渲染器

系列目录

(0) SAP UI5 应用开发人员了解 UI5 框架代码的意义


(1) UI5 module 懒加载机制


(2) UI5 控件渲染机制


(3) HTML 原生事件 VS SAP UI5 Semantic 事件


(4) UI5 控件元数据实现细节


(5) UI5 控件的实例数据实现细节


(6) UI5 控件数据绑定的实现原理


(7) UI5 控件数据绑定的三种模式:One Way,Two Way 和 OneTime 实现原理比较


(8) UI5 控件 ID 的生成逻辑


(9) UI5 控件的多语言(国际化,Internationalization,i18n)支持的实现原理


(10) XML 视图里的 button 控件


(11) button 控件和它背后的 DOM 元素


使用 Jerry 的文章 一个用于SAP UI5学习的脚手架应用,没有任何后台API的依赖,创建一个只包含一个 button 控件的 SAP UI5 应用,用 Chrome 开发者工具里的 Elements 工具栏查看该 button 控件的原生 HTML 代码:



在 Jerry 的前一篇文章 深入学习SAP UI5框架代码系列之一:UI5 Module的懒加载机制,我们已经了解到 UI5 Button Module 之一,ButtonRenderer,专门负责将 sap.ui.commons.button 的实例数据,渲染成原生的 HTML 代码。


在 ButtonRenderer.render 函数里设置断点,然后 F5 刷新页面,断点触发,就可从调用栈观察到 RenderManager 是如何调用 ButtonRenderer 执行渲染工作的。



下图画得有些乱,意图是想表达,最终渲染出的 HTML 源代码里的 button 标签的各个属性,分别是由 ButtonRenderer 哪一行代码实现的。



Jerry 刚刚做 SAP UI5 开发时,了解到 Renderer 机制后,心里有个疑问,SAP UI5 怎么知道 button 控件的渲染器是 ButtonRenderer。换言之,SAP UI5 控件和其渲染器之间的一一对应关系是如何维护的?


SAP UI5 框架里,每类控件都各自维护了一份 Metadata(元数据),其中有个 getRenderer 方法,返回控件对应的渲染器名称。


关于 SAP UI5 控件元数据,本系列后续文章会介绍。



从调试器里能观察到 button 控件元数据里,变量_sRendererName 维护了 button 渲染器的名称:sap.ui.commons.ButtonRenderer. 然而,这个变量在何时赋的值?



从下图第 42971 行能够看出:控件的渲染器满足命名规范:<控件名称>+ "Renderer", 一个简单的字符串拼接操作。



RenderManager 在哪些时刻会开启控件的重绘?


让我们对脚手架应用里的 button 点击事件处理函数稍作修改:每次点击按钮时,调用 setText 修改 button 的 text 属性:



点击按钮,发现 ButtonRenderer.render 再次被触发。



原因在于,oButton1.setText 最终会调用 button 原型链上的 ManagedObject.setProperty 方法,该方法内部有一个显式的 invalidate 调用。


如果忘记了 SAP UI5 控件的原型链设计,可以查看 Jerry 之前的文章:深入学习 SAP UI5 框架代码系列之一:UI5 Module 的懒加载机制。



Control.invalidate 内部经过计算,会得出当前页面需要重绘的区域,最终调用 RenderManager 进行重绘。


我们再来简单了解下 Angular 里的控件绘制。以 SAP Spartacus 的产品转盘(Product Carousel)显示控件为例: 最畅销的产品共有 12 款,分多屏显示在转盘控件里,每屏显示若干个产品。通过控件提供的左右箭头,进行屏与屏之间的切换。转盘底部的小红点,表示当前转盘显示的是第几个屏幕的数据。




SAP UI5 也能实现类似的复合控件,官方称呼为 Custom Control.


Spartacus 产品转盘控件的 HTML 代码表现形式为标签 cx-product-carousel,内部重用了另一个自定义标签 cx-carousel:



当前显示在屏幕里的产品信息,通过 cx-carousel 标签里三个 class 为 item active 的 div 标签显示。



这个自定义产品转盘控件通过 Spartacus 里的 Angular Product Carousel Component 实现。


Product Carousel Component 的 layout 实现里,将 Component 自身的属性 items作为输入,传入另一个 Component cx-carousel, 让其将属性值 title.



因为 cx-carousel 是一个可重用控件,除了显示产品转盘外,还可以用于显示其他同类实体的转盘显示,比如折扣转盘,促销活动转盘等等。因此,除了将 items传入 cx-carousel 之外,还需要告知后者,在转盘内部,以何种布局逻辑显示转盘的每一个元素。


因此,下图第九行通过<ng-template>标签定义了一个 id 为 #carouselItem 的模板,将此 id 一并传入 cx-carousel. 这样,转盘控件在运行时,针对转盘数据源 items$内存储的每一个产品数据,就会按照此模板定义的布局,进行绘制。




当初 Jerry 学习 Spartacus 这个产品转盘的设计时,觉得很亲切,因为其设计思路和 SAP UI5 List Binding(Aggregation Binding)是一致的。


SAP UI5官网上讲解 List Binding 的一个例子:


有一个 companies JSON 数组:



将 companies 路径传入 List 控件,完成了数据源的指定,通知 List 去绘制 companies 数组里的数据。具体渲染哪些数据?List 不知道,需要 items 子控件来定义,比如子控件的 title 属性,显示 JSON 数组的 name 字段,description 属性,显示 JSON 数组的 city 字段。List 会根据 JSON 数组里的 company 节点的个数,动态创建对应数目的 items 子控件。



这里的 SAP UI5 items 子控件,扮演的就是本文之前介绍的 Spartacus 产品转盘控件页面里,用<ng-template>定义出的 id 为 #carouselItem 的模板同样的角色。


感谢阅读,本系列下一篇文章:HTML原生事件 VS SAP UI5 Semantic事件

发布于: 刚刚阅读数: 4
用户头像

Jerry Wang

关注

🏆InfoQ写作平台-签约作者🏆 2017.12.03 加入

SAP成都研究院开发专家,SAP社区导师,SAP中国技术大使。2007 年从电子科技大学计算机专业硕士毕业后加入 SAP 成都研究院工作至今。工作中使用 ABAP, Java, JavaScript 和 TypeScript 进行开发。

评论

发布
暂无评论
深入学习SAP UI5框架代码系列之三:UI5 控件的渲染器_JavaScript_Jerry Wang_InfoQ写作社区