jquery源碼分析(七)——事件模塊 event(二)

上一章節探討了事件的一些概念,接下來看下jQuery的事件模塊。html

 

jQuery對事件的綁定分別有幾個API:.bind()/.live()/.delegate()/.on()/click(),api

      不論是用什麼方式綁定,歸根到底仍是用addEventListener/attachEvent(IE)處理的,正如jQuery的選擇器同樣無論如何匹配最終仍是使用瀏覽器提供的幾個接口處理。瀏覽器

那麼如今就有個疑問,事件爲何還要區分那麼多不一樣的處理方案?函數

      這裏就要涉及到以前提到的 DOM 事件處理模型了,捕獲與冒泡傳統的事件處理給某一元素綁定了一個點擊事件,傳入一個回調句柄處理。element.addEventListener('click',doSomething,false),對比傳統事件來存在這些問題性能

  第一:大量的事件綁定,性能消耗,並且還須要解綁(IE會泄漏);spa

  第二:綁定的元素必需要存在;code

  第三: 後期生成HTML會沒有事件綁定,須要從新綁定htm

  第四: 語法過於繁雜對象

針對這些問題,所以jQuery引進是採用委託的機制思想來處理。blog

     談到事件委託來複習下上節提到的事件模型。DOM 有個事件流的特性,也就是說咱們在頁面上觸發節點的時候事件都會上下或者向上傳播,稱爲事件捕捉和事件冒泡。,DOM2.0 模型將事件處理流程分爲三個階段:事件捕獲階段、事件目標階段、事件起泡階段

                                               

事件傳送能夠分爲3個階段。
(1)在事件捕捉(Capturing)階段,事件將沿着DOM樹向下轉送,目標節點的每個祖先節點,直至目標節點。例如,若用戶單擊了一個超連接,則該單擊事件將從document節點轉送到html元素,body元素以及包含該連接的p元素。在此過程當中,瀏覽器都會檢測針對該事件的捕捉事件監聽器,而且運行這件事件監聽器。
(2)在目標(target)階段,瀏覽器在查找到已經指定給目標事件的事件監聽器以後,就會運行該事件監聽器。目標節點就是觸發事件的 DOM 節點。例如,若是用戶單擊一個超連接,那麼該連接就是目標節點(此時的目標節點其實是超連接內的文本節點)。
(3)在冒泡(Bubbling)階段,事件將沿着DOM樹向上轉送,再次逐個訪問目標元素的祖先節點到document節點。該過程當中的每一步。瀏覽器都將檢測那些不是捕捉事件監聽器的事件監聽器,並執行它們。

換句話說,事件委託就是事件目標自身不處理事件,而是把處理任務委託給其父元素或者祖先元素,甚至根元素(document),如.live()

      對於jQuery中提供多個api來綁定事件:無論你用的是(click / bind / delegate)之中哪一個方法,最終都是 jQuery 底層都是調用 on 方法來完成最終的事件綁定。所以從某種角度來說除了在書寫的方便程度及習慣上挑選,不如直接都採用 on 方法來的痛快和直接使用.on()方法事件處理程序到當前選定的 jQuery 對象中的元素。

  在jQuery 1.11中,.on()方法提供綁定事件處理的全部功能、效果不言而喻了,除了性能的差別,經過委託的事件還能很友好的支持動態綁定,只要 on 的delegate 象是 HTML 頁面原有的元素,因爲是事件的觸發是經過Javascript的事件冒泡機制來監測,因此對於全部子元素(包括後期經過JS生成的元素)全部的事件監聽均能有效,且因爲不用對多個元素進行事件綁定,可以有效的節省內存的損耗。

 

說了這麼多,jQuery提供了這麼多綁定的方法,具體有什麼區別咱們來了解一下:

(1)、.bind()方法:用於直接附加一個事件處理程序到元素上,處理程序附加到 jQuery 對象中當前選中的元素,因此在 .bind() 綁定事件的時候這些元素必須已經存在,很明顯就是直接調用沒利用委託機制。

(2)、live()方法:將委託的事件處理程序附加到一個頁面的 document 元素,從而簡化了在頁面上動態添加的內容上事件處理的使用。這和delegate() 方法相似,只是把全部事件都委託到document對象上來處理,增長冒泡處理時間。如今已經摒棄該方法了,不推薦使用。仍是用例子說明一下:

    $('a').live('click', function() { alert("!")})

jQuery 把 alert 函數綁定到 $(document) 元素上,並使用 ’click’和 ’a’做爲參數。任什麼時候候只要有事件冒泡到 document 節點上,它就查看該事件是不是一個 click 事件,以及該事件的目標元素與’a’這一CSS 選擇器是否匹配,若是都是的話,則執行函數。因爲live缺點太多,這裏就不一一贅述了。

 

(3)、 delegate(): 爲了突破單一 .bind() 方法的侷限性,實現事件委託,引入了.live()方法。後來,爲解決「事件傳播鏈」過長的問題,新版本又支持爲 .live() 方法指定上下文對象。而爲了解決無謂生成元素集合的問題,以後版本乾脆直接引入了一個新方法 .delegate()。

使用 .delegate(),前面的例子能夠這樣寫:

  $('#element).delegate('a', 'click', function() { alert("!!!") });

jQuery 查找(‘#element’),並將click 事件和’a’這一CSS選擇器做爲參數把 alert 函數綁定到(‘#element)上。

       事件監聽原理是:任什麼時候候只要有事件冒泡到$(‘#element)上,它就查看該事件事件類型是不是click事件,以及該事件的目標元素(curTarget)是否與CCS選擇器相匹配。若是都知足就執行函數。能夠注意到,這一過程與.live()相似,可是其把處理程序綁定到具體的元素而非document這一根上,從而大大減小事件傳播過程(事件冒泡過程)。

       因而可知.delegate() 方法是一個相對完美的解決方案。但在DOM結構簡單的狀況下,也可使用.live()。

(4)、on方法:其實 .bind(), .live(), .delegate()都是經過.on()來實現的,.unbind(), .die(), .undelegate()也是同樣的都是經過.off()來實現的,該接口只是提供了一種統一綁定事件的方法


總得來講,雖然bind/delegate/live這三個方法都能實現DOM節點事件綁定,可是能夠用 .on() 來代替上述的 3 種方法

說了這麼多,具體使用過程當中該用那個方法呢?

下面來總結一下:

1. 爲DOM中的不少元素綁定相同事件;
2. 爲DOM中尚不存在的元素綁定事件;
3. 用.bind()的代價是很是大的,它會把相同的一個事件處理程序hook到全部匹配的DOM元素上
4. 不要再用.live()了,它已經再也不被推薦了,並且還有許多問題
5. .delegate()會提供很好的方法來提升效率,同時咱們能夠添加一事件處理方法到動態添加的元素上

實際運用中,事件委託機制(基於事件冒泡)仍存在不足之處:
1. 並不是全部的事件都能冒泡,如load, change, submit, focus, blur
2. 加大管理複雜
3. 很差模擬用戶觸發事件
4. 如何取捨就看項目實際中運用了。
相關文章
相關標籤/搜索