系列目录
(0) SAP UI5应用开发人员了解UI5框架代码的意义
(1) SAP UI5 module懒加载机制
(2) SAP UI5 控件渲染机制
(3) HTML原生事件 VS SAP UI5 Semantic事件
(4) SAP UI5控件元数据的元数据实现
(5) SAP UI5控件的实例数据修改和读取逻辑
(6) SAP UI5控件数据绑定的实现原理
(7) SAP UI5控件数据绑定的三种模式:One Way, Two Way和OneTime实现原理比较(本文)
(8) SAP UI5控件ID的生成逻辑
(9) SAP UI5控件的多语言(国际化,Internationalization,i18n)支持的实现原理
(10) XML视图里的button控件
(11) button控件和它背后的DOM元素
经过了三个多月不懈的努力,Jerry终于初步掌握了使用Angular开发企业级前端应用的技能,也通过阅读Angular源代码的方式,弄清楚了Angular的Property binding,Event binding和Two-way binding的实现原理和区别。
Angular这三种绑定方式的使用语法如下图所示:
但咱们今天的文章不会阐述Angular的数据绑定细节,而是继续聚焦在SAP UI5上。
Jerry 前一篇文章 深入学习SAP UI5框架代码系列之六:SAP UI5控件数据绑定的实现原理,曾经展示过这张源代码截图,第83行包含了SAP UI5支持的三种数据绑定模式:
(1) OneWay:单向绑定
(2) TwoWay:双向绑定
(3) OneTime:单次绑定
从第69行代码得知,SAP UI5模型的默认绑定方式为双向绑定TwoWay.
当我第一次了解了SAP UI5三种不同的数据绑定模式时,脑子里马上浮现出一个问题:
在我们的脚手架应用里,将button控件的text属性,通过bindProperty函数,绑定到JSONModel实例的field_for_text字段上时,使用的是哪一种绑定模式?
oButton1.bindProperty("text", "/field_for_text");
答案是TwoWay,双向绑定。在调试器里,通过下图路径即可查看:
oButton1.mBindingInfos.text.binding.sMode.
方法bindProperty里创建oBinding对象时,把JSONModel的默认binding方式(sDefaultBindingMode), TwoWay, 赋给oBinding对象。
SAP UI5双向绑定的实现原理 - 数据从控件流向模型
我们调用控件的setText方法,修改控件text属性。根据SAP UI5数据双向绑定特性,控件text属性绑定到的模型字段field_for_text的值,也会自动被修改:
oButton1.setText("用js修改控件值");
从上图我们能确认,JSONModel模型实例的field_for_text也跟着被修改了。这一切是怎么发生的?
答案在Jerry之前的文章 深入学习SAP UI5框架代码系列之五:SAP UI5控件的实例数据修改和读取逻辑 介绍的button控件的setText方法里,其实已经提到过。
下图第1320行的代码,执行的逻辑正是在控件属性通过setProperty被更新的场景下,将最新值同步到对应的模型字段中去。
在updateModelProperty函数内部,有一个IF条件判断:只有当前oBinding对象实例的绑定模式为TwoWay时,才调用其setExternalValue方法,将模型字段的对应值,修改成来自控件属性通过setText更改的最新值。
这就是控件text属性的变化,能传递到对应模型字段的原理。
SAP UI5单向绑定的工作原理
通过之前的介绍我们得知,SAP UI5控件绑定的默认模式为TwoWay. 因此,我们如果要测试单向绑定,需要对已有的代码进行修改,将绑定模式显式修改成OneWay:
oButton1.bindProperty("text", "/field_for_text", undefined, "OneWay");
此时,控件text属性通过setText的修改,不会再触发JSONModel模型字段的变化,因为下图3620行IF语句的条件不再成立。这就是SAP UI5单向数据绑定的原理:数据仅仅会在模型字段到控件属性这个方向上单向流动。JSONModel字段值发生变化后,控件对应属性会自动更新。反之,控件属性通过API被修改时,不会引起JSONModel字段值的更新。
SAP UI5单次绑定的工作原理
SAP UI5官方网站上对单次绑定(OneTime)的说明:value is only read from the model once.
怎么理解这句话呢?
通过一个实际的例子来理解双向绑定和单次绑定的区别。
在双向绑定的测试代码里,添加如下两行代码:
myData["field_for_text"] = "Tom"; oModel.checkUpdate();
模型字段field_for_text的初始值,在第28行赋值为Jerry, 然后在第34行设置为Tom. 调用模型的checkUpdate方法后,控件的标签也自动刷新为Tom.
JSONModel的checkUpdate方法,会使用_fireChange,以事件通知的方式,将最新的Tom值广播出去。
that.updateProperty最后会调用SAP UI5控件的setProperty方法,把text属性的值赋成Tom.
下图展示的setProperty方法,在Jerry之前的文章 深入学习SAP UI5框架代码系列之五:SAP UI5控件的实例数据修改和读取逻辑 里有详细介绍。
现在开始测试单次绑定,将32行bindProperty函数调用里的绑定模式改成OneTime:
测试发现,在单次绑定模式下,SAP UI5控件属性和模型字段的自动同步已经中断了——button控件的text属性,保存的是调用bindProperty方法那一刻,JSONModel的field_for_text值Jerry,而不是数据绑定之后,修改成的最新值Tom.
这个行为正是SAP UI5单次绑定的正确表现。
那么为什么在单次绑定模式下,纵然我们调用了模型的checkUpdate方法,仍然无法将模型字段的最新值,通过change事件通知机制告诉给控件的监听函数呢?
答案就是,在SAP UI5控件指定了单次绑定的模式后,它"过河拆桥",马上就把响应模型change事件的监听函数拆除了(detach,取消注册之意)。
奥妙就在下图3379行代码的IF分支里:在SAP UI5控件调用bindProperty方法把控件属性绑定到模型字段时,如果当前绑定模式为OneTime,则取消控件针对模型change事件的监听函数注册。
如此一来,不论接下来模型字段的值如何变化,该变化的值通过change事件进行广播,但UI5控件再也不会收到该事件了,因而控件属性也不会再刷新。
Jerry在SAP UI5 / Angular的实际开发生涯中,一旦遇到数据绑定出问题,总能迅速找到如何排错的突破口,靠的就是对这些前端框架的数据绑定细节的熟悉。
希望本文能帮助大家对SAP UI5官方网站上解释数据绑定三种方式的说明文字,有更深入的理解,感谢阅读。
本系列下一篇文章,我们会介绍SAP UI5控件ID的生成逻辑,敬请期待。