深入学习SAP UI5框架代码系列之三:HTML原生事件 VS UI5 Semantic事件
这是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事件相关推荐
- 深入学习SAP UI5框架代码系列之八:谈谈 SAP UI5 的视图控件 ID,以及 SAP UI5 视图和 Angular 视图的异同
今天是 2021 年 4 月 27 日,周二,SAP 全球心理健康日.SAP 全球的员工,今天放假一天. 这不,早在上周五,我所在的 SAP Spartacus 开发团队的开发经理,就贴心地在 Sla ...
- 深入学习SAP UI5框架代码系列之七:控件数据绑定的三种模式 - One Way, Two Way和OneTime实现原理比较
这是Jerry 2021年的第 8 篇文章,也是汪子熙公众号总共第 279 篇原创文章. 系列目录 (0) SAP UI5应用开发人员了解UI5框架代码的意义 (1) SAP UI5 module懒加 ...
- 深入学习SAP UI5框架代码系列之六:SAP UI5控件数据绑定的实现原理
这是Jerry 2021年的第 7 篇文章,也是汪子熙公众号总共第 278 篇原创文章. 系列目录 (0) SAP UI5应用开发人员了解UI5框架代码的意义 (1) SAP UI5 module懒加 ...
- 深入学习SAP UI5框架代码系列之五:SAP UI5控件的实例数据修改和读取逻辑
这是Jerry 2021年的第6篇文章,也是汪子熙公众号总共第277篇原创文章. 系列目录 (0) SAP UI5应用开发人员了解UI5框架代码的意义 (1) SAP UI5 module懒加载机制 ...
- 深入学习SAP UI5框架代码系列之四:SAP UI5控件的元数据实现
这是Jerry 2021年的第5篇文章,也是汪子熙公众号总共第276篇原创文章. 系列目录 (0) SAP UI5应用开发人员了解UI5框架代码的意义 (1) UI5 module懒加载机制 (2) ...
- 深入学习SAP UI5框架代码系列之二:UI5 控件的渲染器
这是Jerry 2020年的第79篇文章,也是汪子熙公众号总共第261篇原创文章. 系列目录 (0) SAP UI5应用开发人员了解UI5框架代码的意义 (1) UI5 module懒加载机制 (2) ...
- 深入学习SAP UI5框架代码系列之一:UI5 Module的懒加载机制
本文是深入学习SAP UI5框架代码系列的第二篇文章. 系列目录 SAP UI5应用开发人员了解UI5框架代码的意义 UI5 module懒加载机制 UI5 控件渲染机制 HTML原生事件 VS SA ...
- webbrowser控件 加载为空白_深入学习SAP UI5框架代码系列之一:UI5 Module的懒加载机制...
本文是深入学习SAP UI5框架代码系列的第二篇文章. 系列目录 SAP UI5应用开发人员了解UI5框架代码的意义 UI5 module懒加载机制 UI5 控件渲染机制 HTML原生事件 VS SA ...
- 通过最简单的button控件,深入学习SAP UI5框架代码系列之零
Jerry曾经作为SAP成都研究院的Fiori应用开发人员,从事了将近3年的SAP CRM Fiori应用开发,在使用SAP UI5的过程中,遇到过形形色色的问题,不少都是通过调试SAP UI5框架代 ...
最新文章
- BZOJ 4025 二分图
- Barts PE Builder——Windows系统维护完全图形化攻略
- 理解Hinted Handoff
- Unity中那些事半功倍的好插件
- linuxMint下安装ftp工具--filezilla
- html5 canvas图文编辑器源码_5个微信编辑器,再也不用为公众号发愁啦
- java图书管理系统技术难度_Java图书管理系统练习程序(一)
- Python学习-集合的常见用法
- 解决:VScode 汉化后 、设置中文后 还显示英文的问题
- 论文笔记(Neural Graph Collaborative Filtering)
- jsp页面获取系统的日期时间
- Python之数据分析(figure图形对象、Numpy连线特殊点、图像多元布局)
- 【shell】echo不显示变量中的多个空格
- 确定要离开当前页面吗
- 网络安全笔记-信息安全工程师与网络安全工程师考试大纲(附:Web安全大纲)
- python炫酷烟花表白源代码-python炫酷烟花表白的源代码分享
- Gym - 100886I 2015-2016 Petrozavodsk Winter Training Camp, Saratov SU Contest I - Archaeological Res
- matplotlib折线图(标记点、标记点大小、标记点边颜色、标记点边宽)
- 无人驾驶动态避障策略调研 | 机器人动态避障策略 | 行人轨迹预测 | 机器人导航
- pands 画图 调整大小_图片处理小技巧(调整大小、批量命名),超级实用