JavaScript事件流

大魔王薩格拉斯發表於2015-11-23
  1. 什麼是JS事件流

  早期的IE事件傳播方向為由上至下,即從document逐級向下傳播到目標元素;而Netscape公司的Netscape Navigator則是朝相反的方向傳播,

也就是從目標元素開始向上逐級傳播最終至window。

  後來ECMAScript在DOM2中對事件流進行了進一步規範,基本上就是上述二者的結合。當事件發生時,最先得到通知的是window,然後是document,由上至下逐級依次而入,直到真正觸發事件的那個元素(目標元素)為止,這個過程就是捕獲。接下來,事件會從目標元素開始起泡,由下至上逐級依次傳播,直到window物件為止,這個過程就是冒泡。

  如果我們有下面的HTML程式碼結構

 1 <div class="box" id="box2">
 2             <div class="box" id="box3">
 3                 <div class="box" id="box4">
 4                     <div class="box" id="box5">
 5                         <div class="box" id="box6">
 6                             <h3>點我開始!!</h3>
 7                         </div>
 8                     </div>
 9                 </div>
10             </div>
11         </div>

  那麼當我們點選box6中的HE以後,事件的觸發過程也就是這樣的:

  

    

    2.DEMO例項

    我在Gitbub上放了一個DEMO用於演示JS事件的傳播原理,大家感興趣的話可以前往檢視。

    http://xiaoyunchen.github.io/JavaScriptEvent/

    開啟頁面後點選中央的"點我開始",也就是從最裡層觸發click事件,然後頁面將演示事件是如何進行捕獲和冒泡兩個階段的傳播的。

    

    同樣在瀏覽器控制中也可以清楚的看出了JS事件的傳播過程:

    

    哦對了,程式碼原始碼放在了 https://github.com/xiaoyunchen/JavaScriptEvent 感興趣的同學可以自行前往檢視。

    

    3.有何用處

    瞭解了JS事件流的傳播原理,那麼對我們的實際開發過程中有什麼作用呢?

    首先來看DOM2新增事件的方法申明:

element.addEventListener(event, function, useCapture);
/*
第一個引數是事件的型別 (如 "click" 或 "mousedown").
第二個引數是事件觸發後呼叫的函式。
第三個引數是個布林值用於描述事件是冒泡還是捕獲。該引數是可選的。
*/

  也就是說我們可以控制是在冒泡還是捕獲階段去處理事件,但是由於考慮瀏覽器相容性的問題,這裡一般我們都只是用false即冒泡階段。

  另外,根據事件的冒泡原理,我們還可以實現另外一個很重要的功能:事件委託

  比如我們上面的程式碼中,有很多元素都需要新增事件,按照之前的做法,我們需要去依次獲取每個元素,然後再為每個事件新增上監聽事件,

  但是這樣會帶來一些問題:

  1.多次操作DOM獲取元素,勢必會降低瀏覽器處理效能

  2.事件不具有繼承性,如果我們動態在頁面中新增了一個元素,那麼還需要重新走一遍上述程式為其新增監聽事件

  好在我們通過JS事件的冒泡原理來解決上述問題:我們只監聽最外層的元素,然後在事件函式中根據事件來源進行不同的事件處理。

  這樣的話,我們新增事件監聽時只需要操作一個元素,極大的降低了DOM訪問,同時也方便的監聽事件的移除。而且就算動態在頁面新增一個元素時,也不用

  重複為其新增監聽事件,因為它的事件會自動冒泡到外層被我們給截獲。(這也是jquery中時間繫結的實現原理。)

  

  4.事件委託DEMO

   同樣的,我建立了一個簡單的DEMO用於樣式事件委託: http://xiaoyunchen.github.io/JavaScriptEvent/delegate.html

   在這個頁面中,我們建立了兩個列表,然後在兩個列表的父級新增了一個事件委託,攔截了列表元素的所有click事件。

  當我們點選兩個列表的任何列表元素時,事件都能得到正確的響應,在控制檯列印出對應的元素ID值,

  當然哪怕是我們後臺動態新增的li元素,不用再為其單獨繫結事件,也可以得到正確的響應,這就是JS事件委託的作用。

  

  (注意,並不是所有事件都支援事件委託,比如mouseover,mouseout等就不支援事件委託。)

  測試DEMO的原始碼同樣放在了 https://github.com/xiaoyunchen/JavaScriptEvent 感興趣的同學可以自行前往檢視。

 

  小結:

    JavaScript中的事件流分為捕獲階段、目標階段、冒泡階段,我們可以JS控制需要操作捕獲還是冒泡階段的事件。

    根據事件流的原理,我們可以優化事件處理方法,比如進行事件委託。

相關文章