那么jQuery事件處理機制能幫我們處理那些問題?
- 毋容置疑首先要解決瀏覽器事件兼容問題
- 可以在一個事件類型上添加多個事件處理函數,可以一次添加多個事件類型的事件處理函數
- 提供了常用事件的便捷方法
- 支持自定義事件
- 擴展了組合事件
- 提供了統一的事件封裝、綁定、執行、銷毀機制
- ……
為了更深入的理解幕后的實現,所以先整理整體的結構思路,從1.7后就去除了live綁定,所以現在的整個事件的API
如圖:
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事件的流程圖
在綁定階段與執行階段
那么JQuery為了更好的對事件的支持內部又做了哪些額外的優化操作?
兼容性問題處理:
瀏覽器的事件兼容性是一個令人頭疼的問題。IE的event在是在全局的window下, 而mozilla的event是事件源參數傳入到回調函數中。還有很多的事件處理方式也一樣
JQuery提供了一個 event的兼容類方案
jQuery.event.fix 對游覽器的差異性進行包裝處理
例如:
- 事件對象的獲取兼容,IE的event在是在全局的window,標准的是event是事件源參數傳入到回調函數中
- 目標對象的獲取兼容,IE中采用srcElement,標准是target
- relatedTarget只是對於mouseout、mouseover有用。在IE中分成了to和from兩個Target變量,在mozilla中 沒有分開。為了保證兼容,采用relatedTarget統一起來
- event的坐標位置兼容
- 等等
事件的存儲優化:
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內部實現的分析了


