在前文《在Ext JS 5使用ViewControllers》中,简单的介绍了Ext JS 5的一项重要改进——声明式事件监听。在本文,将深度探讨如何使用声明式事件监听啦简化应用程序的视图并减少自定义组件的样板代码。

注意:文章假设你使用的是Ext JS 5.0.1或更高版本。

什么是声明式事件监听?

所谓的“声明式事件监听”,就是指定义在类主体中的监听或在实例的配置对象中使用了listeners配置项。以这种方式来声明事件监听不是Ext JS 5的新功能。在Ext JS 4,可以正在类中声明事件监听,不过只适于处理函数或作用域已定义的情况,例如:

  1. Ext.define('MyApp.view.User', {
  2. extend: 'Ext.panel.Panel',
  3. listeners: {
  4. // 函数必须内联或在之前已被定义:
  5. collapse: function() {
  6. // respond to panel collapse here
  7. }
  8. },
  9. //该方法不能被定义为collapse的处理函数:
  10. onCollapse: function() {
  11. }
  12. });

由于所需的处理函数不能使用类中定义的方法,因而声明式监听在Ext JS 4中的使用有限。开发人员通常会通过重写initComponent方法并使用on方法来添加监听:

  1. Ext.define('MyApp.view.User', {
  2. extend: 'Ext.panel.Panel',
  3. initComponent: function() {
  4. this.callParent();
  5. this.on({
  6. collapse: this.onCollapse,
  7. scope: this
  8. });
  9. },
  10. onCollapse: function() {
  11. console.log(this); // the panel instance
  12. }
  13. });

作用域解析

在Ext JS 5,对listeners配置项做了改进,允许将事件处理指定为字符串来对应方法名。在运行时(触发事件的任何时候),框架会将这些方面解析为实际的函数引用。我们将这一过程称为事件监听作用域解析。

在Ext JS 4,如果明确给出了“作用域”,才能解析字符串处理程序。而在Ext JS 5,在声明“字符串”处理程序而没有明确声明作用域的时候,为默认作用域解析添加了一些特殊规则。

作用域解析有两种结果:组件或视图控制器(ViewController)。无论是哪种结果,都会从组件开始搜索。作用域可能是组件,也可能是视图控制器,如果不是,框架会“爬”到组件的上层直到找到适合的组件或视图控制器。

解析作用域为组件

框架解析作用域的第一种方式是寻找defaultListenerScope配置项为true的组件。对于类中的事件监听声明,搜索会从组件自身开始。

  1. Ext.define('MyApp.view.user.User', {
  2. extend: 'Ext.panel.Panel',
  3. xtype: 'user',
  4. defaultListenerScope: true,
  5. listeners: {
  6. save: 'onUserSave'
  7. },
  8. onUserSave: function() {
  9. console.log('user saved');
  10. }
  11. });

监听被定义在了用户视图的类主体,这意味着框架在提升层次之前会先检查用户视图自身的defaultListenerScope。在当前示例,用户视图将defaultListenerScope设置为了true,那当前监听的作用域将会被解析为用户视图。

对于事件监听被声明在实例配置项的情况,将会条过组件自身,框架会从父容器开始搜索,请参考以下代码:

  1. Ext.define('MyApp.view.main.Main', {
  2. extend: 'Ext.container.Container',
  3. defaultListenerScope: true,
  4. items: [{
  5. xtype: 'user',
  6. listeners: {
  7. remove: 'onUserRemove'
  8. }
  9. }],
  10. onUserRemove: function() {
  11. console.log('user removed');
  12. }
  13. });

对于用户视图的监听是在实例的配置对象中声明的,这意味着框架会跳过用户视图(尽管它定义了defaultListenerScope为true),且会解析为主视图。

解析作用域为视图控制器

在Ext JS 5,引入了新的控制器类型——Ext.app.ViewController。在《在Ext JS 5使用ViewControllers》中详细介绍了视图控制器,因此这里只讨论与视图控制器与事件监听有关的部分。

与Ext.app.Controller可以管理许多视图不同,每一个视图控制器实例只能绑定一个视图实例。视图与视图控制器之间之间一对一的关系允许视图控制器作为视图或视图的条目中事件监听声明的默认作用域。

对于defaultListenerScope,规则同样适用于视图控制器。类层的监听总是会在搜索组件的上层之前先搜索组件自身的视图控制器。

  1. Ext.define('MyApp.view.user.User', {
  2. extend: 'Ext.panel.Panel',
  3. controller: 'user',
  4. xtype: 'user',
  5. listeners: {
  6. save: 'onUserSave'
  7. }
  8. });
  9. Ext.define('MyApp.view.user.UserController', {
  10. extend: 'Ext.app.ViewController',
  11. alias: 'controller.user',
  12. onUserSave: function() {
  13. console.log('user saved');
  14. }
  15. });

上述监听被声明在用户视图的类主体内,由于用户视图有它自己的控制器,框架会解析作用域为UserController。如果用户视图没有自己的控制器,那么作用域会解析到上层。

另一方面,实例层监听会跳过组件并解析为视图控制器上层的父容器,例如:

  1. Ext.define('MyApp.view.main.Main', {
  2. extend: 'Ext.container.Container',
  3. controller: 'main',
  4. items: [{
  5. xtype: 'user',
  6. listeners: {
  7. remove: 'onUserRemove'
  8. }
  9. }]
  10. });
  11. Ext.define('MyApp.view.main.MainController', {
  12. extend: 'Ext.app.ViewController',
  13. alias: 'controller.main',
  14. onUserRemove: function() {
  15. console.log('user removed');
  16. }
  17. });

合并listeners配置项

在Ext JS 4,在基类声明的监听会被子类或实例的listeners配置项的声明完全重写。在Ext JS 5,改进了listeners的API,可适当的合并在基类、子类和实例中的事件监听声明。要想了解其中的行为,可查看以下示例:

  1. Ext.define('BaseClass', {
  2. extend: 'Ext.Component',
  3. listeners: {
  4. foo: function() {
  5. console.log('foo fired');
  6. }
  7. }
  8. });
  9. Ext.define('SubClass', {
  10. extend: 'BaseClass',
  11. listeners: {
  12. bar: function() {
  13. console.log('bar fired');
  14. }
  15. }
  16. });
  17. var instance = new SubClass({
  18. listeners: {
  19. baz: function() {
  20. console.log('baz fired');
  21. }
  22. }
  23. });
  24. instance.fireEvent('foo');
  25. instance.fireEvent('bar');
  26. instance.fireEvent('baz');

在Ext JS 4,上面示例只会输出“baz”,但在Ext JS 5,listeners配置项会被正确的合并并输出“foo bar baz”。这就允许类在需要的时候才去声明监听而不需要知道超类是否已经有了监听。

小结

我们任务声明式的监听可大大简化应用程序中的事件监听定义。结合视图控制器用于处理应用程序的逻辑和视图模型的双向绑定,还可以尽可能的改进应用程序的开发体验。尝试去让我们知道你的想法。

Ext JS 5的声明式事件监听的更多相关文章

  1. cocos2d JS touch屏幕点击事件监听 cc.EventListener.TOUCH

    var self = this; this.touchListener = cc.EventListener.create({ event: cc.EventListener.TOUCH_ONE_BY ...

  2. Ext JS学习第十六天 事件机制event(一) DotNet进阶系列(持续更新) 第一节:.Net版基于WebSocket的聊天室样例 第十五节:深入理解async和await的作用及各种适用场景和用法 第十五节:深入理解async和await的作用及各种适用场景和用法 前端自动化准备和详细配置(NVM、NPM/CNPM、NodeJs、NRM、WebPack、Gulp/Grunt、G

    code&monkey   Ext JS学习第十六天 事件机制event(一) 此文用来记录学习笔记: 休息了好几天,从今天开始继续保持更新,鞭策自己学习 今天我们来说一说什么是事件,对于事件 ...

  3. Node.js 教程 05 - EventEmitter(事件监听/发射器 )

    目录: 前言 Node.js事件驱动介绍 Node.js事件 注册并发射自定义Node.js事件 EventEmitter介绍 EventEmitter常用的API error事件 继承EventEm ...

  4. [JS]笔记12之事件机制--事件冒泡和捕获--事件监听--阻止事件传播

    -->事件冒泡和捕获-->事件监听-->阻止事件传播 一.事件冒泡和捕获 1.概念:当给子元素和父元素定义了相同的事件,比如都定义了onclick事件,点击子元素时,父元素的oncl ...

  5. [No00006A]Js的addEventListener()及attachEvent()区别分析【js中的事件监听】

    1.添加时间监听: Chrom中: addEventListener的使用方式: target.addEventListener(type, listener, useCapture); target ...

  6. js 事件监听 冒泡事件

    js 事件监听  冒泡事件   的取消 [自己写框架时,才有可能用到] <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitiona ...

  7. js 事件监听 兼容浏览器

    js 事件监听 兼容浏览器   ie 用 attachEvent   w3c(firefox/chrome)  用 addEventListener 删除事件监听 ie 用 detachEven   ...

  8. JS通用事件监听函数

    JS通用事件监听函数 版本一 //把它全部封装到一个对象中 var obj={ readyEvent:function (fn){ if(fn==null){ fn=document; } var o ...

  9. js 事件监听封装

    var eventUtil={//添加句柄 //element,节点 //type,事件类型 //handler,函数 addHandler:function(element,type,handler ...

随机推荐

  1. [转]Golang之struct类型

    http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=22312037&id=3756923 一.struct        ...

  2. alt text 与 tooltip区别

    在做工具的Accessiblity测试时, 对于image对象,一直分不清它的alt属性与tooltip属性的区别与用法, 从网上查了下, 比较认同这样的观点: alt属性: alternative ...

  3. 第二个Sprint冲刺第九天

    讨论地点:宿舍 讨论成员:邵家文.李新.朱浩龙.陈俊金 工作:接着昨天的任务

  4. 第一次sprint团队贡献分改

    201306114322 邵家文 50分 201306114319 陈俊金 10分 201306114320 李新    10分 201306114324 朱浩龙 10分

  5. 《MORE EFFECTIVE C++》条款27 要求或者禁止对象分配在堆上

    1. 要求对象分配在堆上 临时对象一般是存在于栈中的,或者是静态对象存在于常量存储区的.那么当创建一个这样的对象的时候,一般是需要隐式或显式地调用构造函数,在销毁的时候调用析构函数的.可以从这方面入手 ...

  6. LeetCode Permutations (全排列)

    题意: 给出n个元素,请产生出所有的全排列. 思路: 注意到可能会有相同的排列出现,比如 {2,2}.还有可能是乱序列(大部分情况下都是无所谓的). 递归(1):产生的过多的多余vector. cla ...

  7. linux/lib/string.c

    /** * strlen - Find the length of a string * @s: The string to be sized */ size_t strlen(const char ...

  8. (基础篇) php中0与空 Null false的区别

    <?php $test=0; if($test==''){ echo '<br />在php中,0即为空'; //被输出 } if($test===''){ echo '<br ...

  9. Prepared Java infrastructure for distributed scenarios

    code is sited on: https://github.com/zhoujiagen/javaiospike progress 2015/5/27 Nio/Nio2 examples, us ...

  10. 阅读《构建之法》第八、九、十章有感和Sprint总结

    1.阅读<构建之法>读后感 第八章:需求分析 需求分析,我觉得需求分析挺重要的,一个需求分析是指对要解决的问题进行详细的分析,弄清楚问题的要求,包括需要输入什么数据,要得到什么结果,最后应 ...