首先来看看jQuery.event的dispatch方法node
dispatch: function( event ) { // 对event对象进行修正 event = jQuery.event.fix( event ); var i, j, ret, matched, handleObj, handlerQueue = [], args = slice.call( arguments ), // 读取事件缓存 handlers = ( data_priv.get( this, "events" ) || {} )[ event.type ] || [], special = jQuery.event.special[ event.type ] || {}; // 将参数一重置为jQuery的事件对象 args[0] = event; // 添加delegate属性,用于事件代理 event.delegateTarget = this; if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { return; } // 取得事件队列 handlerQueue = jQuery.event.handlers.call( this, event, handlers ); // 对于事件队列的处理 i = 0; while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) { event.currentTarget = matched.elem; j = 0; while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) { // Triggered event must either 1) have no namespace, or 2) have namespace(s) // a subset or equal to those in the bound event (both can have no namespace). if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) { event.handleObj = handleObj; event.data = handleObj.data; ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) .apply( matched.elem, args ); if ( ret !== undefined ) { if ( (event.result = ret) === false ) { event.preventDefault(); event.stopPropagation(); } } } } } // Call the postDispatch hook for the mapped type if ( special.postDispatch ) { special.postDispatch.call( this, event ); } return event.result; },
通读整段代码,概括一下,jQuery.event.dispatch是作了一下几项处理的jquery
先看第一点缓存
对event对象的修复,这一步获得event对象,是jQuery的event对象,而非原生的对象。这里jQuery将本来只读的对象,变为了一个可读可写的对象,这样就能够对其进行随意操做了。不过对于event对象修复,我打算现将其放到下一章与事件的修复一块儿进行讲解,所以这里只须要知道,这里是返回的jQuery的event对象就好了。app
第二点也再也不多说,就是读取了事件的缓存函数
那么来到第三点,也是事件分发的另一个重点post
在以前版本的jQuery中,队列的生成与处理,都是放在了dispatch中进行,不过现在队列已经交由jQuery.event.handlers生成并返回,那么咱们首先来看下获取到了handlerQueue究竟是什么,即也就是对于jQuery.event.handlers来进行阅读。this
handlers: function( event, handlers ) { var i, matches, sel, handleObj, handlerQueue = [], delegateCount = handlers.delegateCount, cur = event.target; // 判断是不是事件代理、与是不是鼠标左键的点击事件 if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) { // 从事件源开始,遍历所有祖先元素到绑定事件的元素为止 for ( ; cur !== this; cur = cur.parentNode || this ) { // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) // 不对disabled的元素进行click的处理 if ( cur.disabled !== true || event.type !== "click" ) { // 收集符合条件的事件句柄 matches = []; for ( i = 0; i < delegateCount; i++ ) { handleObj = handlers[ i ]; // 获取selector sel = handleObj.selector + " "; if ( matches[ sel ] === undefined ) { // 匹配事件句柄 matches[ sel ] = handleObj.needsContext ? jQuery( sel, this ).index( cur ) >= 0 : jQuery.find( sel, this, null, [ cur ] ).length; } if ( matches[ sel ] ) { matches.push( handleObj ); } } if ( matches.length ) { handlerQueue.push({ elem: cur, handlers: matches }); } } } } // 在事件队列中,增长其余直接绑定的事件句柄 if ( delegateCount < handlers.length ) { handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) }); } return handlerQueue; }
这一部分,总体看来比较复杂,咱们来理一下一下。spa
这部分先对事件代理作了判断并进行了处理,采用match来对符合条件的事件句柄作一个筛选,并将全部符合条件的事件句柄,按从深及浅的顺序,一一放入了事件队列之中。代理
而后,在处理完成了事件代理以后,采用delegateCount区分事件代理以及直接绑定,再将直接绑定的事件句柄,放入事件队列之中,生成了最终的事件队列。这样,最终获得的,就是一个委托层次越深,便越会提早执行的事件队列。code
所以,事件委托,在这一步就已经完成了。同时,由于jQuery的事件处理机制,是这样一个队列的形式,所以,以前在第一章末尾所说起的,对于执行顺序的问题,这里也很好的解决了。
那么最后,咱们来看dispatch中如何对于这个事件队列进行的处理。
// 对于事件队列的处理 i = 0; while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) { event.currentTarget = matched.elem; j = 0; while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) { if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) { event.handleObj = handleObj; event.data = handleObj.data; //执行事件回调函数 ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) .apply( matched.elem, args ); //直接return false,便可event.preventDefault以及stopPropagation if ( ret !== undefined ) { if ( (event.result = ret) === false ) { event.preventDefault(); event.stopPropagation(); } } } } }
这一部对于事件队列进行了有序的执行(由深及浅再到自己),而后,在这个过程当中,经过已经修正过的jQuery事件对象,动态的改变event对象的属性,在执行事件句柄。同时,也对return false后,直接调用event.preventDefault(),与event.stopPropagation()进行了处理。
那么,到目前,对于事件绑定这一块,除了对于事件的修复部分,其余的部分都已经阅读完毕。咱们到最后再来理一下整个的过程。
那么下一章,将对jQuery事件对象的修复,以及事件的修复,进行一个讲解。