前幾章已經把最核心的實現都分解過了,這一章咱們看看jQuery是如何實現事件模擬的html
在Internet Explorer 8和更低,一些事件change
和 submit
自己不冒泡,但jQuery修改這些冒泡,建立一致的跨瀏覽器的行爲。web
blur :瀏覽器
在這個事件觸發前,元素已經失去焦點,不冒泡,同步觸發。target 指向當前失去焦點的元素。緩存
focus:函數
在這個事件觸發前,元素已經獲得焦點,不冒泡,同步觸發。target 指向當前獲得焦點的元素。spa
與此同時DOM Level 3 事件模塊 還定義了 focusin ,focusout 以及 DOMFocusIn ,DOMFocusOut 四個事件。3d
focusin :代理
在當前元素得到焦點前以及相關元素失去焦點前觸發,可冒泡,同步觸發。target 指向當前將要得到焦點的元素,relatedTarget 指向失去焦點的元素code
focusout :htm
在當前失去焦點前觸發,可冒泡,同步觸發。target 指向當前將要失去焦點的元素,relatedTarget 指向將要失去焦點的元素。
DOMFocusIn :
在這個事件觸發前,元素已經獲得焦點,可冒泡,同步觸發。target 指向當前獲得焦點的元素。
DOMFocusOut :
在這個事件觸發前,元素已經沒有焦點,可冒泡,同步觸發。target 指向當前失去焦點的元素
1, 全部 IE 版本均支持focusin/focusout事件(注意:IE6/7/8中不支持el.addEventListener方法)。
2, Opera 最強悍即支持attachEvent,又支持addEventListener。且這兩種方式添加事件均支持focusin/focusout事件。
3, Safari/Chrome 給人一個驚喜,雖然el.onfocusin方式不支持,但 addEventListener方式卻支持。所以想讓Safari/Chrome中支持focusin事件,只能使用addEventListener方式添加事件。
4, Firefox 任何一種添加事件方式都不支持 focusout/focuso
那麼如何在全部的平臺上都兼容focusin/focusout?
這個方法在event.add,event.dispatch等幾個事件的處理地方都會被調用到,jQuert.event.special 對象用於某些事件類型的特殊行爲和屬性
換句話說就是某些事件不是大衆化的的事件,不能一律處理,好比 load 事件擁有特殊的 noBubble 屬性,能夠防止該事件的冒泡而引起一些錯誤
因此須要單獨針對處理,可是若是都寫成判斷的形式,顯然代碼結構就不合理了,並且不方便提供給用戶自定義擴展
在webkit下的截圖,特殊事件類型
大致上針對9種事件,不一樣狀況下處理hack,咱們具體分析下焦點事件兼容冒泡處理,處理大同小異
針對focusin/ focusout 事件jQuery.event.special擴充2組處理機制,
special.setup方法主要是來在Firefox中模擬focusin和focusout事件的,由於各大主流瀏覽器只有他不支持這兩個事件。
因爲這兩個方法支持事件冒泡,因此能夠用來進行事件代理
var attaches = 0, handler = function( event ) { jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); }; jQuery.event.special[ fix ] = { setup: function() { if ( attaches++ === 0 ) { document.addEventListener( orig, handler, true ); } }, teardown: function() { if ( --attaches === 0 ) { document.removeEventListener( orig, handler, true ); } } };
前面的分析咱們就知道經過事件最終都是經過add方法綁定的,也就是addEventListener方法綁定的,可是在add方法以前會有一個過濾分支
之前看不懂代碼,如今回過來恍然大悟了,原來這個方法是這樣用的
因此最終代碼會跑到各類的Hack中了,
可見對focusin/ focusout 的處理,沒有用通用的方法,並且是直接用的special.setup中的綁定
幾個重點
1 綁定的是focusin/ focusout 事件,內部確換成了focus/blur事件
2 document.addEventListener( orig, handler, true );事件綁在document上,最後是true,用的捕獲綁定
3 jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );方法
由於火狐不支持focusin/ focusout事件,因此要找個全部瀏覽器都兼容相似事件,對了那就是focus/blur,
可是focus/blur不能冒泡丫,怎麼辦?
咱不是還有捕獲嗎?
那麼利用捕獲怎麼模擬出冒泡呢?
jQuery.event.simulate = function( type, elem, event, bubble ) { // 重寫事件 var e = jQuery.extend( new jQuery.Event(), event, { type: type, isSimulated: true, originalEvent: {} } ); // 若是要冒泡 if ( bubble ) { // 利用jQuery.event.trigger模擬觸發事件 jQuery.event.trigger( e, null, elem ); } else { // 不然利用jQuery.event.dispatch來執行處理 jQuery.event.dispatch.call( elem, e ); } // 若是須要阻止默認操做,則阻止 if ( e.isDefaultPrevented() ) { event.preventDefault(); } }
能夠看到focusin/ focusout 可冒泡事件實現原理是
1 focusin 事件添加事件處理程序時,jQuery 會在 document 上會添加 handler 函數
2 在事件捕獲階段監視特定元素的 focus/ blur 動做,捕獲行爲發生在 document 對象上,這樣纔能有效地實現全部元素都能能夠冒泡的事件。
3 程序監視到存在 focus/ blur 行爲,就會觸發綁定在 document 元素上的事件處理程序,該事件處理程序在內部調用 simulate 邏輯觸發事件冒泡,以實現咱們但願的能夠冒泡事件。
4 以後利用jQuery.event.trigger模擬觸發事件,把從target-document的元素都過濾出來,分析每一個節點上是否綁定了事件句柄,依次處理,按照必定的規範,好比是否有事件阻止之類的,這裏就再也不重複分析了jQuery.event.trigger http://www.cnblogs.com/aaronjs/p/3452279.html
咋一看其實原理都挺簡單的, 可是jQuery爲了實現兼容統一,可謂煞費苦心了,把事件冒泡與捕獲都統一模擬了一遍