一,基本原理


1.1 数据缓存 data


在事件之前是应该先讲解下data的实现的,因为在event的实现中,需要用到data,用来存储用户在element上注册的事件回调函数,这个data的实现比较简单,所以在这里简单说一下。


$.data可以在一个元素上存储数据,比如$('xxx').data("a", 1)。实现原理很简单,先初始化一个cache对象,然后在元素上添加一个唯一的id属性,这个id对应一个object,然后把这个对应关系存储在cache中。


这样调用data的时候,就可以根据元素上的唯一id去cache中取出一个对象,然后在这个对象上做增删查改的操作即可。


需要注意的一点是,Data函数是在闭包中的,无法直接访问,而jquery帮我们初始化了两个data,分别是data_priv和data_user,即一个是私有的,一个是给用户用的。所以jquery很多模块内部实现会用到data来存储数据,但是你调用data却无法读取到,就是这个原因,jquery内部用的是data_priv来存储的,而用户调用的时候用的是data_user来存储的。




1.2 event的基本实现


还记得dom事件模型吗,0级事件模型和2级事件模型。因为浏览器的实现问题,ie下的二级事件模型只有冒泡而没有捕获过程。而且ie的添加事件的方法名和事件的event对象都和其他浏览器不一样。所以jquery对这个做了一个封装。




event的基本原理也很简单。jquery会调用data方法在element上存储一个events对象和一个handle函数(不要再问我为什么你用data读出来是undefined,参见1.1中的解释data_priv和data_user的解释)。然后把所有的回调函数都存在这个events对象里,events对象的结构如下:

{ 

     click: queue 

     dbclick:queue 

     change:queue 

     keyup:queue 

     … 

}



其中handle是一个jquery构造的回调函数,这个函数才是原生事件触发时直接调用的函数,这个函数定义如下:


eventHandle = elemData.handle = function( e ) { 

                    // Discard the second event of a jQuery.event.trigger() and 

                    // when an event is called after a page has unloaded 

                    return typeof jQuery !== strundefined && (!e || jQuery.event.triggered !== e.type) ? 

                         jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : 

                         undefined; 

               };



     


其作用就是调用再次调用用户注册的回调函数。


然后就是每个事件名称都对应一个队列,当你调用jqueryapi注册事件时,你的回调函数会被放到对应的队列中,比如click就会放在click队列中。




举个例子总结下。假设执行代码 $("a").click(b);其中b是一个函数,那么jquery的执行过程是:


1,调用data_priv读取handle函数和events对象


2,存储b到events.click队列中


3,调用原生api把handle注册为回调函数


然后触发事件的时候会通过handle函数来调用b,说白了handle就是一个代理而已。




二,源码结构




2.1 helper 对象 jQuery.event


jQuery.event 是一个helper对象,它是事件机制的真正实现,其他的api比如 on, click什么的都是对他的封装而已。基本结构如下:


jQuery.event = { 

     add: function(){} 

     remove: function(){} 

     trigger: function(){} 

     dispatch: function(){} 

     handlers: function(){} 

     fix: function(){} 

     special: function(){} 

}

说说每个函数的作用:


add 


在一个元素上注册一个事件,其实现过程在上面已经说过了,具体实现细节就不谈了。


remove


删除一个事件


trigger:触发事件,这里是触发浏览器原生的事件,注意其中有这么一行代码:elem[ type ]();


dispatch:事件分发,注意和trigger的区别,trigger是触发原生事件,而dispatch只是调用jquery注册的事件。如果你调用trigger,其会触发原生事件,然后原生事件会触发handle函数,handle函数会调用dispatch来调用你之前用jquery注册的其他回调函数。


handlers:返回用户注册的回调函数队列


fix:修正event参数


special:处理一些特殊的事件,比如onload focus等等




2.2 jQuery.Event


这是回调函数中的event参数,这里做了标准化的处理,因此所有的浏览器中的event参数都会保持一致的api




2.3 封装api


因为有了 event和Event,下面就是封装了各种接口,最终都是调用event中的对应方法来实现的,后面依次定义了这些接口:on, one, off, trigger。




2.4 别名:


在event.alias中定义了一堆别名,本质只是一个快捷方式而已,比如click其实就是on("click"),hover就是mouseenter和mouseleave