首先來看看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事件對象的修復,以及事件的修復,進行一個講解。