ExtJs 事件机制浅析

     闲来无事,拿来ExtJs的原码,研究一翻。先给大家讲讲ExtJs的事件机制。先来看看Ext.util.Observable这个类,关于这个类的介绍,注释里的解释是:

     Abstract base class that provides a common interface for publishing events. Subclasses are expected to
 to have a property "events" with all the events defined.
 For example:
  Employee = function(name){
    this.name = name;
    this.addEvents({
        "fired" : true,
        "quit" : true
    });
 }
 Ext.extend(Employee, Ext.util.Observable);

 

所有需要事件机制的类都是需要从这个类继承的,我关注到这个类也是因为从Ext.Component开始的,因为Ext.Component就是从Ext.util.Observable继承过来的。闲话少叙,来看代码: 

 

 这段代码相当于Ext.util.Observable的构造函数,看这段函数,主要调用了on函数,参数为属性listeners,on方法是什么?继续看代码:

Ext.util.Observable.prototype.addListener  方法呢?再看:

这段代码的逻辑看似复杂,其实只需要从第130行开始看即可,前面的代码实则是在作参数的转换,为别一种形式的传参作准备,也即前面调用这段代码的传参形式(传一个包含多个事件处事器的对象),从这个方法中我们可以看出在Ext.util.Observable类中有个属性events,events有点类型 map对象,即包含多对 事件名和Ext.util.Event的一一对应,这里又引入了一个类Ext.util.Event.这段代码里调用Ext.util.Observable本身和事件名作为参数调用了Ext.util.Event的构造方法,new 了一个Ext.util.Event对象,然后又用fn, scope, o三个参数再去调用了Ext.util.Event的addListener方法。

下面就来看Ext.util.Event的构造方法:

 

很简单,三个属性name 、 obj 、liseners .构造函数的参数为name 和 obj赋了值.

再来看addListener方法:

 

我这里把关于 Ext.util.Event类的包含的所有方法都贴了来了,一是因为这个类比较小,二是因为要理解addListener这个方法,必须结合其它方法来看才能弄明白。首先从前面的构造方法中我们看到 Ext.util.Event类有个listeners属性,其实该属性表面上看是个数组对象,这个数组对象是用来存储事件处事器的,一个Ext.util.Event对象有一个事件名,但是可以包含多个事件处理器,这里所说的事件处理器并不JS中的function,它实际上也是一个对象,通过createListener函数来构造,其形式为{fn: fn, scope: scope, options: o} ,我们在调用addListener方法的时候便是通过createListener函数来构造一个事件处理器,然后再将其加到Ext.util.Event的listeners数组中的,

 

 

 

看到这里我想大家应该能对Ext.util.Observable有一个概貌了,什么样的概貌呢?   Ext.util.Observable中一个events数组,数组中存的是eventName 和Ext.util.Event对象的映射,而Ext.util.Event中又包含有多个形式为{fn: fn, scope: scope, options: o} 的事件处理器,事件处理器中的fn即为真正的事件处理函数,即Ext.util.Observable的一个事件名是可以对应到多个事件处理器的,我们可以称之为事件理处器链。这只是对于Ext.util.Observable对象的属性的内部结构的一个大致子解。当然对于其如何加载事件处理器,如何触发,事件处理顺序等都还要详细分析.

 

 

 

 

 

  • 事件加载

        事件加载在前面都介绍过了,是通过Ext.util.Observable对象的addListener函数,这个函数还有一个别名为on,它们是等价的,从代码里可以看出来,引入on这个别名只是为了方便起见。这个函数的参数有四个:eventName, fn, scope, o 前两个很好理解:事件名和触发函数,至于后面两个参数的作用后面再说。一个eventName 对应由fn,scope,o组成的Ext.util.Event对象。它们以map中的一项的形式存储在events属性中,events是一个map数组的形式,调用一次addListener函数,便向其中加入一项这样的映射条目。

 

 

  • 卸载事件

 

看代码,可只这里说的卸载并不是卸载掉关于eventName我对应的所有处理器,只是卸载掉对于eventName 的关于fn,和scope和处理器,前面我们说过了,一个eventName对于的不只是一个事件处理器,对应的是一个事件处理器链,这个事件处理器链的构造是由xt.util.Event类来实现的,所以卸载事实上只是从对应的事件处理器链上拿掉一个事件处理器。

 

  • 事件触发

   事件触发是通过调用Ext.util.Observable类的fireEvent,第一些个参数名是事件名,然后事件名对应的Ext.util.Event类会触发fire方法,依次调用该对象事件处理器链上的方法,大家如果看Ext.util.Event类的原码会发现在这个对象中有一个变量firing,为boolean类型.在fire方法中去触发事件处理器链之前和之后会先后将这个变量设为true和false,这个变量的作用主要是为了防止在触发事件正在作用的过程中,往事件链上增加和移除事件处理器.可时是为了防止JS数组的同步问题。不过我对这个问题也没详细研究过,只是在看原码的过程中,猜测这个变量的作用的。

 

  • 其它

    如果看Observable.js这个文件,在这个类中还有个方法:getMethodEvent  ,我大概看了下,它的主要作用是为继承自这个类的方法,增加拦截器,在以在调用方法前和调用方法后增加拦载方法。

 

 

 

测试:

 

 

 

 

在IE中执行上述代码,先后会弹出"I am eating!'  和  'I finished eating!'.正如我们预计的那样。现在我们改换一下代码。

 

 

 

 

 

 

 

 

 

 


 

执行上述代码后,我们可以看到两条语句是以相反的顺序出来的。这是因为加了选项的原因.

 

 

 

在上述代码中,我们测试的是关于方法拦截器的例子,执行上述代码可以看到,sayHello方法的确是被拦截了!

 

 

 

原码中的BUG:

关于Ext.util.Observable中的上述方法:addEvents是有BUG的,第188行处,因为 this.events[a[i]] = true;  不过这个BUG在实际使用Ext时并不会暴露出来,主要是因为这段代码本身意义不大,并没有执行实际有用的动作,大家可以去研究一下Ext.Component组件,在这个组件的构造函数中就会执行addEvents方法.(注我看的源码版本是:2.0.2).

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值