jQuery 2.0.3 源碼分析 事件體系結構


那么jQuery事件處理機制能幫我們處理那些問題?

  1. 毋容置疑首先要解決瀏覽器事件兼容問題
  2. 可以在一個事件類型上添加多個事件處理函數,可以一次添加多個事件類型的事件處理函數
  3. 提供了常用事件的便捷方法
  4. 支持自定義事件
  5. 擴展了組合事件
  6. 提供了統一的事件封裝、綁定、執行、銷毀機制
  7. ……

為了更深入的理解幕后的實現,所以先整理整體的結構思路,從1.7后就去除了live綁定,所以現在的整個事件的API

如圖:

image

 


jQuery的事件綁定有多個方法可以調用,以click事件來舉例:

  • click方法
  • bind方法
  • delegate方法
  • on方法
$('#foo').click(function(){ })

$('#foo').bind('click',function(){ })

$("foo").delegate("td", "click", function() { });

$("foo").on("click", "td", function() { });

以上四種綁定都能達到同一樣的效果,但是各自又有什么區別,內部又是如何實現?

 


源碼分析

 

click方式

jQuery.each( ("blur focus focusin focusout load resize scroll unload 
click
 dblclick " +
        "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
        "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {

        // Handle event binding
        jQuery.fn[ name ] = function( data, fn ) {
            return arguments.length > 0 ?
                this.on( name, null, data, fn ) :
                this.trigger( name );
        };
    });

源碼很簡單,合並15種事件統一增加到jQuery.fn上

內部調用this.on / this.trigger

 

bind方式

bind: function( types, data, fn ) {
    return this.on( types, null, data, fn );
},
unbind: function( types, fn ) {
    return this.off( types, null, fn );
},

同樣調用的this.on/this.off

 

delegate方式

delegate: function( selector, types, data, fn ) {
    return this.on( types, selector, data, fn );
},
undelegate: function( selector, types, fn ) {
    // ( namespace ) or ( selector, types [, fn] )
    return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
}

同樣調用的this.on/this.off

 

one方式

one: function( types, selector, data, fn ) {
    return this.on( types, selector, data, fn, 1 );
},

還是this.on

 

可見以上的接口只是修改了不同的傳遞參數,最后都交給on實現的

 


實現最簡單的事件委托

給父元素綁定事件,子元素也能響應


 

其實委托的原理都是一樣的,通過事件對象過濾出關聯目標的hack,做相對應的處理,那么JQuery是如何實現的呢?

 


jQuery事件的流程圖

在綁定階段與執行階段

image

 

 


 

那么JQuery為了更好的對事件的支持內部又做了哪些額外的優化操作?

 

兼容性問題處理:

瀏覽器的事件兼容性是一個令人頭疼的問題。IE的event在是在全局的window下, 而mozilla的event是事件源參數傳入到回調函數中。還有很多的事件處理方式也一樣

JQuery提供了一個 event的兼容類方案

jQuery.event.fix 對游覽器的差異性進行包裝處理

例如:

  1. 事件對象的獲取兼容,IE的event在是在全局的window,標准的是event是事件源參數傳入到回調函數中
  2. 目標對象的獲取兼容,IE中采用srcElement,標准是target
  3. relatedTarget只是對於mouseout、mouseover有用。在IE中分成了to和from兩個Target變量,在mozilla中 沒有分開。為了保證兼容,采用relatedTarget統一起來
  4. event的坐標位置兼容
  5. 等等

 

事件的存儲優化:

jQuery並沒有將事件處理函數直接綁定到DOM元素上,而是通過$.data存儲在緩存$.cahce上,這里就是之前分析的貫穿整個體系的緩存系統了

聲明綁定的時候:

  • 首先為DOM元素分配一個唯一ID,綁定的事件存儲在$.cahce[ 唯一ID ][ $.expand ][ 'events' ]上,而events是個鍵-值映射對象,鍵就是事件類型,對應的值就是由事件處理函數組成的數組,最后在DOM元素上綁定(addEventListener/ attachEvent)一個事件處理函數eventHandle,這個過程由 jQuery.event.add 實現。

執行綁定的時候:

  • 當事件觸發時eventHandle被執行,eventHandle再去$.cache中尋找曾經綁定的事件處理函數並執行,這個過程由 jQuery.event. trigger 和 jQuery.event.handle實現。
  • 事件的銷毀則由jQuery.event.remove 實現,remove對緩存$.cahce中存儲的事件數組進行銷毀,當緩存中的事件全部銷毀時,調用removeEventListener/ detachEvent銷毀綁定在DOM元素上的事件處理函數eventHandle。

 

事件處理器:

jQuery.event.handlers

針對事件委托和原生事件(例如"click")綁定 區分對待

事件委托從隊列頭部推入,而普通事件綁定從尾部推入,通過記錄delegateCount來划分,委托(delegate)綁定和普通綁定。

 

其余一些兼容事件的Hooks

fixHooks,keyHooks,mouseHooks

 


總的來說對於JQuery的事件綁定

在綁定的時候做了包裝處理

在執行的時候有過濾器處理

 

下章就開始深入on內部實現的分析了


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM