1. 程式人生 > >jQuery 2.0.3 原始碼分析 事件體系結構

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內部實現的分析了