上一章对于jQuery的事件系统,对于jQuery的一些事件绑定接口做了分析。同时,引入了事件委托的概念。那么,从本章起,将开始深入到jQuery的事件系统内部,对于其源码进行解析。
这一篇是可以独自拿出来看,与前面两章虽然有些关系,但是如果只是对于jQuery源码有兴趣的,并且对前端事件有些理解的,从这章开始看也是可以的。
on方法
上一章提及到jQuery绑定的核心,是落在了on方法身上的。on方法相当于对于jQuery的事件接口进行了统一,让jQuery其他事件绑定有关的方法,直接调用on方法来进行实现。因此,我们将拿on方法作为jQuery事件一开始的一个突破口,来对jQuery事件进行层层分析。下面来看jQuery的on方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
on : function( types, selector, data, fn, /*INTERNAL*/ one ) { var origFn, type; // Types can be a map of types/handlers /* * 第一个参数传入为对象的处理,类似 * {“event1name”:function(){}, * "event2name":function(){} * } * 这样的写法。 * 然后调用自身on方法,分别对其进行on方法绑定事件 */ if ( typeof types === "object" ) { // ( types-Object, selector, data ) if ( typeof selector !== "string" ) { // ( types-Object, data ) data = data || selector; selector = undefined; } for ( type in types ) { this.on( type, selector, data, types[ type ], one ); } return this; } //对于data与fn为null的情况下的处理 if ( data == null && fn == null ) { // ( types, fn ) fn = selector; data = selector = undefined; //对于仅仅fn为null的情况下的处理 } else if ( fn == null ) { if ( typeof selector === "string" ) { // ( types, selector, fn ) fn = data; data = undefined; } else { // ( types, data, fn ) fn = data; data = selector; selector = undefined; } } //如果执行函数直接是false的情况的处理returnFalse即是直接return False的函数 if ( fn === false ) { fn = returnFalse; } else if ( !fn ) { return this; } //如果最后一个参数为1,那么直接调用fn,并解绑。 if ( one === 1 ) { origFn = fn; fn = function( event ) { // Can use an empty set, since event contains the info jQuery().off( event ); return origFn.apply( this, arguments ); }; // Use same guid so caller can remove using origFn fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); } //直接调用jQuery.event.add并传入处理好的参数 return this.each( function() { jQuery.event.add( this, types, fn, data, selector ); }); } |
可以发现,作为绑定核心的on方法,其实质上只是对传进来的参数进行调整处理,并将处理过后的参数,传入jQuery.event.add中来进行处理,因此,接下来我们将对jQuery.event.add的源码来进行分析与阅读。
jQuery.event.add方法
这个方法比较长,并且内部有许多东西,暂时还不好去读,因此,我将这一部分分为几个部分来进行阅读。为了方便理解,我将其分成几个部分,然后一一来解读。我尽量做到对这一部分的讲解做到简单易懂,解读过程中有不对的地方,还请指出。同时,这一部分的代码,除非特别说明,否则全部来自于jQuery.event.add。
绑定部分
首先,我们先直接跳到事件注册那一部分,即addeventListener,看看他做了些什么
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// Init the event handler queue if we're the first // 如果是第一次,那么初始化事件队列 if ( !(handlers = events[ type ]) ) { handlers = events[ type ] = []; handlers.delegateCount = 0; // Only use addEventListener if the special events handler returns false // 如果获取特殊事件失败,那么采用addEventListener来进行事件注册 if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { if ( elem.addEventListener ) { // 注册时将eventHandle来进行注册,并且仅仅执行一次 elem.addEventListener( type, eventHandle, false ); } } } |
这段代码,实际就是对于handlers的初始化,同时,对事件采用addEventListenr进行了绑定。
在这一段代码中,我们可以看出,jQuery在绑定事件时,与以下几个部分有关:
- eventHandle
- events
- handlers
- special
下面将对这几个部分,以及这几个部分衍生出来的部分一一进行解读。同时,以下几部分代码,为了方便阅读,对本身这部分的代码进行了一些抽象(这词用到这里怎么怪怪的),方便于理解
eventHandle部分
1 2 3 4 5 6 7 8 9 10 11 12 |
//获取数据缓存 var elemData = data_priv.get( elem ); ... // 如果elemData没有handle属性,给其初始化一个handle属性 if ( !(eventHandle = elemData.handle) ) { 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 && jQuery.event.triggered !== e.type ? jQuery.event.dispatch.apply( elem, arguments ) : undefined; }; } |
这里首先对于我们要操作的结点下的数据缓存进行了获取,同时,将数据缓存下的handle属性,赋给了eventHandle。这里可以发现,elemData.handle这一部分,并没有直接对于事件的回调函数进行处理,而是进一步的使用jQuery.event.dispatch来进行的处理。
jQuery.event.dispatch这里还不会进行阅读,我们只要知道,jQuery对于回调的处理,和jQuery.event.dispatch这部分有关就行了。
events以及handlers部分
1 2 3 4 5 6 7 8 9 |
var //获取数据缓存 elemData = data_priv.get( elem ), events; ... // Init the element's event structure and main handler, if this is the first // 如果elemData没有events属性,给其初始化一个events属性 if ( !(events = elemData.events) ) { events = elemData.events = {}; } |
events部分,来自于要操作节点下的数据缓存中的events属性。而根据之前的操作
1 2 3 4 5 6 |
// Init the event handler queue if we're the first // 如果是第一次,那么初始化事件队列 if ( !(handlers = events[ type ]) ) { handlers = events[ type ] = []; ... } |
可以明白,events即是对于操作节点下各种事件的类型进行的记录。
handlers部分
1 2 3 4 5 6 7 8 9 10 11 |