这是Jerry 2020年的第80篇文章,也是汪子熙公众号总共第262篇原创文章。

系列目录

(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元素

本文将讨论SAP UI5控件的事件处理,全文会围绕下图表现出的差异来阐述。

首先用一个简单的例子来回顾HTML原生事件处理原理。

有这样一个简单的HTML页面,里面使用了一个HTML原生button标签,通过οnclick="copyText"注册了一个名为copyText的事件处理函数。

点击按钮之后,响应函数copyText将Field1的值拷贝到Field2去。这个通过onclick注册的事件处理函数,在Chrome开发者工具里可以直接查看。

除了onclick之外,调用浏览器原生的addEventListener方法也能给DOM元素注册事件。

在企业级web应用里,DOM树的结构通常都不简单。例如仅仅包含一个简单button控件的SAP UI5应用,页面渲染出来后也会自动生成5个div标签:

如果每个需要响应事件的控件,都使用onclick或者addEventListener给DOM元素注册一个事件处理函数,随着DOM事件处理函数数量的增加,web应用的性能会降低。因此SAP UI5引入了另一种所谓Semantic(语义)事件的概念,来完成UI5控件的事件注册和响应工作。

使用Jerry文章 一个用于SAP UI5学习的脚手架应用,没有任何后台API的依赖 提到的脚手架,开发一个只包含sap.ui.commons.button的UI5应用:

上图的Elements标签页里,显示的是SAP UI5应用渲染完毕后,生成的HTML原生代码。里包含的button标签的生成逻辑,我们已经在前一篇文章 深入学习SAP UI5框架代码系列之二:UI5 控件的渲染器 里介绍过了。

我们采用与前一个原生HTML button例子同样的操作方式,在Chrome开发者工具里检查UI5应用里该button的Event Listeners,却什么也没发现。

选中"Ancestors"前面的勾之后,一下子显示了很多条目出来:

展开条目中的click,发现SAP UI5把click事件注册在button标签的父节点,即id为content的div标签上了,如下图所示。

再看看UI5应用里sap.ui.commons.Button的事件注册代码:

这里并没有出现HTML原生事件click的身影,而将一个包含了属性名称press,值为JavaScript函数的JavaScript对象,作为输入参数,传入了UI5 Button的构造函数里:

用户点击这个按钮时,触发的应该是名称为click的事件,和我们在这里为press事件注册的处理函数有什么关系?

在UI5 button的实现源代码里能找到答案。切换到Chrome开发者工具的Sources标签页,快捷键Ctrl + O,输入button,选择第一个结果Button-dbg.js:

这里能看到,press作为button支持的事件,定义在Button-dbg.js里:

下面这段代码的含义是,当UI5 button有click事件发生时,如果其本身处于enabled并且是visible状态,则fire一个Press事件(this.firePress()):

因此,正是Button实现里的这个onclick函数,实现了从事件click映射到事件press的任务。

上图调试器里168行的this.firePress调用,最终如何成功地调用到UI5程序里针对press事件注册的处理函数的呢?

还记得这个系列的前一篇文章 深入学习SAP UI5框架代码系列之一:UI5 Module的懒加载机制 里介绍的一个知识点吗?

SAP UI5运行时为所有的Module维护了一个注册表,以键值对的数据结构存储了这些Module的信息,键的数据类型为string,值类型即window.eval()将加载好的JavaScript文件内容作为输入参数,执行后返回的JavaScript对象。

类似的原理,SAP UI5里每个控件都维护了一个键值对结构的事件注册表mEventRegistry, 键的数据类型string,存储事件名称,值类型为数组,里面存放了针对该事件,应用程序实现的响应函数。

下图展示的是我脚手架应用里的button控件的事件注册表,只包含一条记录,键为press,值为一个数组,里面唯一的元素即我在脚手架应用里实现的包含了alert调用的事件响应函数。

下图展示的逻辑是:

(1) SAP UI5框架从第237行的控件事件注册表里,根据事件名称press,取出存放其事件处理函数的数组;

(2) 遍历该数组,在for循环里用JavaScript function原型提供的call方法,对这些响应函数进行调用,完成事件响应:

至此又引出了一个新的问题:button控件的事件注册表mEventRegistry里的那唯一的条目,是何时填充进去的?

再回忆本系列第一篇文章里介绍的SAP UI5控件的原型链:

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

UI5应用里这一行语句:

new sap.ui.commons.Button()

会依次执行控件原型链上每一个节点对应的构造函数。控件事件注册表mEventRegistry的填充操作,就发生在EventProvider这个节点的构造函数里:

上图的变量oValue,就是我new一个button实例时传入的press事件的处理函数。在第1192行代码里,调用attachPress将oValue指向的函数进行注册。函数attachPress最终调用EventProvider的attachEvent方法,将键值对写入mEventRegistry:

至此有最后一个问题还未解答:本文开头部分展示的Chrome开发者工具里,SAP UI5页面渲染后生成的button标签,在Event Listeners一栏里观察不到任何响应函数。而在其父节点,id为content的div标签里,在click事件下却能观察到响应函数。

Button父节点的div标签上的click方法,和本文讨论了这么长时间的button事件注册表里的press事件,到底有何关系?

按钮被点击时,查看调试器里显示的调用栈最外一层,发现SAP UI5的jquery-dbg.js, 响应的是HTML原生的click事件,且触发该事件的对象的的确确是id为content的div标签,而不是button标签,这一点可以从event.currentTarget的值来确认。

以上图调用栈中绿色的线为分隔,绿线下方的代码,处理的是HTML原生的点击事件click,同时完成了将click事件,经div投递给其子节点,button标签的任务。

绿线上方的Button.onclick, 前文我们已经阐述过,通过this.firePress将click事件映射成press事件,后续SAP UI5的所有事件处理,均围绕这个press事件进行。

按照SAP UI5开发团队大佬Andreas Kunz的介绍,button这种press事件称为Semantic事件。同HTML原生的click事件直接通过onclick或addEventListener注册在HTML DOM元素上不同,Semantic event的注册和调用都是通过SAP UI5框架的JavaScript代码施加在SAP UI5自行实现的控件上,比HTML原生的DOM事件处理和响应轻量得多,能避免随着DOM树复杂度的增加而造成的应用性能下降。

引入Semantic事件后,UI5控件不直接响应HTML原生事件,而是通过一个叫做UIArea的实体,来接收用户触发的HTML原生事件,并将其dispatch给UI5控件,后者再将其映射成一一对应的Semantic事件,并调用应用程序里实现的响应函数。这里的UIArea可以类比成设计模式里的Facade(外观)模式,对SAP UI5的应用开发人员屏蔽了底层事件映射的复杂度。

上图的UIArea的详细描述,在SAP UI5官方文档里有记载。

下图高亮的一段对UIArea的阐述,展开来讲就是Jerry本文的内容,大家感兴趣的可以移步这个链接继续阅读。

如果把本文提到的Semantic事件换个叫法,比如称其为虚拟事件,那么很容易联想到Angular,Vue和React里引入的Virtual DOM(虚拟DOM)概念。从本质上说,这些前端框架都采取增加框架实现复杂度的代价,引入一个中间抽象层,来减少直接在JavaScript层操作DOM层造成的性能开销。

顺便说一句,AngularJS里的控件注册实现,同SAP UI5思路一致:同样未采取将事件处理函数直接注册到HTML DOM元素上的机制。

下图是一个Angularjs应用,第22行的ng-click指令,告诉Angularjs框架,超链接被点击后,根据模型字段name,进行排序。

Angularjs框架如何解析这个ng-click指令,并完成事件注册的?

在Angularjs应用bootstrap阶段,框架会遍历HTML DOM tree,递归调用compileNodes方法,逐一解析每一个包含了ng指令的元素:

当解析到包含了ng-click = "sortField = ‘name’"的a标签时,调用Angular元素element的on方法,进行事件注册:

查看on方法的实现代码可知:Angularjs也并未将事件响应函数注册到DOM元素上,而是同SAP UI5一样,在框架内维护了一个控件事件注册表,this.$$listeners(SAP UI5的名称叫做mEventRegistry),采用键值对的数据结构,来存储事件名称和其对应的事件响应函数。

Angularjs应用里,事件响应函数被调用时的调用栈截图:

关于SAP UI5和Angularjs的事件处理机制比较的更多细节,可以参考我的SAP社区博客:

Compare Event handling mechanism: SAPUI5 and Angular

本系列下一篇文章介绍的内容: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框架代码系列之三:HTML原生事件 VS UI5 Semantic事件相关推荐

  1. 深入学习SAP UI5框架代码系列之八:谈谈 SAP UI5 的视图控件 ID,以及 SAP UI5 视图和 Angular 视图的异同

    今天是 2021 年 4 月 27 日,周二,SAP 全球心理健康日.SAP 全球的员工,今天放假一天. 这不,早在上周五,我所在的 SAP Spartacus 开发团队的开发经理,就贴心地在 Sla ...

  2. 深入学习SAP UI5框架代码系列之七:控件数据绑定的三种模式 - One Way, Two Way和OneTime实现原理比较

    这是Jerry 2021年的第 8 篇文章,也是汪子熙公众号总共第 279 篇原创文章. 系列目录 (0) SAP UI5应用开发人员了解UI5框架代码的意义 (1) SAP UI5 module懒加 ...

  3. 深入学习SAP UI5框架代码系列之六:SAP UI5控件数据绑定的实现原理

    这是Jerry 2021年的第 7 篇文章,也是汪子熙公众号总共第 278 篇原创文章. 系列目录 (0) SAP UI5应用开发人员了解UI5框架代码的意义 (1) SAP UI5 module懒加 ...

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

    这是Jerry 2021年的第6篇文章,也是汪子熙公众号总共第277篇原创文章. 系列目录 (0) SAP UI5应用开发人员了解UI5框架代码的意义 (1) SAP UI5 module懒加载机制 ...

  5. 深入学习SAP UI5框架代码系列之四:SAP UI5控件的元数据实现

    这是Jerry 2021年的第5篇文章,也是汪子熙公众号总共第276篇原创文章. 系列目录 (0) SAP UI5应用开发人员了解UI5框架代码的意义 (1) UI5 module懒加载机制 (2) ...

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

    这是Jerry 2020年的第79篇文章,也是汪子熙公众号总共第261篇原创文章. 系列目录 (0) SAP UI5应用开发人员了解UI5框架代码的意义 (1) UI5 module懒加载机制 (2) ...

  7. 深入学习SAP UI5框架代码系列之一:UI5 Module的懒加载机制

    本文是深入学习SAP UI5框架代码系列的第二篇文章. 系列目录 SAP UI5应用开发人员了解UI5框架代码的意义 UI5 module懒加载机制 UI5 控件渲染机制 HTML原生事件 VS SA ...

  8. webbrowser控件 加载为空白_深入学习SAP UI5框架代码系列之一:UI5 Module的懒加载机制...

    本文是深入学习SAP UI5框架代码系列的第二篇文章. 系列目录 SAP UI5应用开发人员了解UI5框架代码的意义 UI5 module懒加载机制 UI5 控件渲染机制 HTML原生事件 VS SA ...

  9. 通过最简单的button控件,深入学习SAP UI5框架代码系列之零

    Jerry曾经作为SAP成都研究院的Fiori应用开发人员,从事了将近3年的SAP CRM Fiori应用开发,在使用SAP UI5的过程中,遇到过形形色色的问题,不少都是通过调试SAP UI5框架代 ...

最新文章

  1. BZOJ 4025 二分图
  2. Barts PE Builder——Windows系统维护完全图形化攻略
  3. 理解Hinted Handoff
  4. Unity中那些事半功倍的好插件
  5. linuxMint下安装ftp工具--filezilla
  6. html5 canvas图文编辑器源码_5个微信编辑器,再也不用为公众号发愁啦
  7. java图书管理系统技术难度_Java图书管理系统练习程序(一)
  8. Python学习-集合的常见用法
  9. 解决:VScode 汉化后 、设置中文后 还显示英文的问题
  10. 论文笔记(Neural Graph Collaborative Filtering)
  11. jsp页面获取系统的日期时间
  12. Python之数据分析(figure图形对象、Numpy连线特殊点、图像多元布局)
  13. 【shell】echo不显示变量中的多个空格
  14. 确定要离开当前页面吗
  15. 网络安全笔记-信息安全工程师与网络安全工程师考试大纲(附:Web安全大纲)
  16. python炫酷烟花表白源代码-python炫酷烟花表白的源代码分享
  17. Gym - 100886I 2015-2016 Petrozavodsk Winter Training Camp, Saratov SU Contest I - Archaeological Res
  18. matplotlib折线图(标记点、标记点大小、标记点边颜色、标记点边宽)
  19. 无人驾驶动态避障策略调研 | 机器人动态避障策略 | 行人轨迹预测 | 机器人导航
  20. pands 画图 调整大小_图片处理小技巧(调整大小、批量命名),超级实用

热门文章

  1. 山东理工OJ【2121】数据结构实验之链表六:有序链表的建立(插排法)
  2. linux中下载文件的命令
  3. 一个亿万富翁和一个陌生人的换钱计划
  4. Sharepoint学习笔记—Ribbon系列-- 3.在Ribbon中找到正确的Location
  5. 又一次回到追寻梦想的地方
  6. 使用Hexo搭建博客,备份至GitHub过程(基于网上资料的实践操作)
  7. CF613D Kingdom and its Cities
  8. 转载:Django之Form组件
  9. oracle 数据库,用户管理以及表空间等相关基础操作
  10. ArcGIS License启动无响应