写点什么

深入学习 SAP UI5 框架代码系列之五:SAP UI5 控件的实例数据修改和读取逻辑

作者:Jerry Wang
  • 2021 年 11 月 28 日
  • 本文字数:2166 字

    阅读完需:约 7 分钟

深入学习 SAP UI5 框架代码系列之五:SAP UI5 控件的实例数据修改和读取逻辑

SAP UI5 控件的 set 和 get 方法,作为通过 JavaScript 代码给前端控件设置属性值和读取属性值的最常用两个方法,广泛应用于 SAP UI5 程序中。


本文我们将通过研究 button 控件的 setText 和 getText 方法实现,来学习 SAP UI5 控件的实例数据修改和读取逻辑。


下图是一段简单的 SAP UI5 代码:每点击一次 button,就会在 press 事件的响应函数里,给 button 的 text 属性值尾部附上一个字符“1”.



点了三次按钮后,其渲染出的 HTML 代码如下图所示,button 的 text 属性后面多了三个"1":



单步调试进入 setText 方法内部,发现该方法最终执行的实现是 ManagedObject.setProperty:



我们可以通过上图右边调用栈里实现,复习本系列之前文章学到的两个知识点:


(1) 文章 深入学习SAP UI5框架代码系列之一:UI5 Module的懒加载机制 里提到的 SAP UI5 控件的原型继承链:


Button->Control->Element->ManagedObject->EventProvider->BaseObject


(2) 文章 HTML原生事件 VS SAP UI5 Semantic 事件 里提到的从 HTML 原生的 click 事件到 SAP UI5 press 语义事件的映射逻辑。

setProperty 的实现逻辑概述

注释写得很棒,不过 setProperty 的代码本身的执行逻辑也很清晰。



第 1295 行 this.mProperties 即 SAP UI5 控件的实例数据存储结构。上图右上角 Watch 面板里的含义是,当前 setProperty 方法调用,需要修改 text 属性,修改成新的值为"Button1".


1295 行首先从 this.mProperties 中取出 text 属性修改前的值,存储在变量 oOldValue 里。


1298 行调用 this.validateProperty 方法,检查传入 setProperty 的输入参数,即待修改的属性值 oValue 是否有效。


1300 行判断修改前的值 oOldValue,和待修改的输入值 oValue 是否相同。如果相同,当前 setProperty 调用没必要继续执行,直接返回。


在 validateProperty 内部,SAP UI5 框架根据本系列前一篇文章 深入学习SAP UI5框架代码系列之四:SAP UI5 控件的元数据实现 描述的逻辑, 取出控件 text 属性的元数据,得知该属性类型为 string,访问权限为 public:



每个不同类型的 SAP UI5 控件属性,根据其元数据的 type 字段,可以得到一个对应的类型描述器,如上图 1409 行 oType 所示。


描述器里包含一系列方法,其中 normalize 函数负责在写入新的属性值时,对输入值进行规则化处理。



在 setProperty 调用时,最后一个可选的输入参数 bSuppressInvalidate,默认值为 undefined,因此会执行 1316 行的 invalidate 方法,触发 UI 的重绘操作(rerendering)。



上图第 1313 行只是将新的属性值写入 SAP UI5 控件的实例数据存储结构里,该行代码执行完毕后,UI 上的 button 标签文本并不会变化。


只有当 UI 界面重绘完成后,用户才能在浏览器里看到 button 标签的最新值。


上图 1316 行的 invalidate 方法,会以异步的方式触发 UI 重绘操作。异步操作的调度,采用 JavaScript 原生函数 setTimeout, 该函数将 renderPendingUIUpdates 这个任务添加到 JavaScript 引擎任务队列的尾部,这样主线程一旦空闲(因为 setTimeout 第二个参数,即超时时间指定为 0),就会执行 renderPendingUIUpdates,以重绘 UI 区域里需要重绘,即属性值发生了变化的那些控件。



Button 控件的重绘,最终通过其对应的渲染器,ButtonRenderer 来实现,具体的渲染方法 render 的调用,如上图右部标注了数字 4 的调用栈栈帧所示。


关于 SAP UI5 控件的渲染器,请查看 Jerry 之前的文章 深入学习SAP UI5框架代码系列之二:UI5 控件的渲染器


再回到 ManagedObject.setProperty 的方法主体。


1320 行的 this.updateModelProperty, 涉及到 SAP UI5 控件对应的模型更新,在代码 1319 行注释里提到,如果控件使用双向绑定方式同一个模型绑定,那么当 UI 控件属性发生变化时,对应的模型字段也应该被更新。这个模型字段的更新就实现在 1320 行的 updateModelProperty 函数里,Jerry 的下一篇文章 UI5 控件数据绑定的实现原理 会介绍。



ManagedObject.setProperty 的末尾,会调用实现在原型链节点 EventProvider 上的 fireEvent 方法,抛出一个_change 事件,包含发生该事件的控件 id,发生 change 的属性名称,变化前和变化后的属性值。



虽然事件名称_change 前面的下划线表明该事件用于 SAP UI5 框架内部处理,然而这只是一个弱约束,我们依旧可以在自己的应用程序里,使用下图高亮区域里 button 控件的 attachEvent 方法,来监听这个事件。


下图右部分调试器 Watch 面板里展示的是_change 事件的负载,表明一个 id 为__button0 的控件,text 属性值从 Jerry 变成了 Jerry1.



以上就是 button 控件的 setText->setProperty 的执行逻辑的大致介绍,了解了 SAP UI5 控件数据修改的原理,理解 getText 就容易多了。


前面介绍 setProperty 的时候提到了执行 UI 重绘的异步操作,发生在 renderPendingUIUpdates 函数里,这里 button 控件的渲染器 ButtonRenderer 的 render 方法会被调用。渲染器又调用 button 的 getText 方法,取出待渲染的 button 标签值。



而 getText 同 setText 类似,转而调用 ManagedObject 的 getProperty 方法:



getProperty 的核心逻辑比 setProperty 简单得多,直接从控件实例数据存储结构 mProperties 里取出对应需要读取的属性值。



顺便说一句,Angular 同 SAP UI5 一样,也有类似的 UI 异步重绘操作。


每当 Angular 内部维护的微任务队列为空时,(onMicrotaskEmpty), 触发 tick 操作:



tick 操作调用 detectChanges 函数(相当于 SAP UI5 的 renderPendingUIUpdates), detectChanges 会递归调用 refreshView, 刷新发生了属性变化的 Angular 控件。



本系列的下一篇文章,我会介绍 SAP UI5 控件数据绑定的实现原理,感谢阅读。

发布于: 3 小时前阅读数: 7
用户头像

Jerry Wang

关注

个人微信公众号:汪子熙 2017.12.03 加入

SAP成都研究院开发专家,SAP社区导师,SAP中国技术大使。

评论

发布
暂无评论
深入学习 SAP UI5 框架代码系列之五:SAP UI5 控件的实例数据修改和读取逻辑