當咱們給元素綁定好單擊事件,單擊這個元素,就會執行相應的代碼,可是若是這個元素的父元素、祖先元素都綁定了單擊事件,他們會執行嗎?他們的執行順序是什麼呢?javascript
能夠嘗試把頁面理解爲一個二維的平面,想象有一張白紙,咱們在這張紙上畫下了一層一層的同心圓,當咱們用手指按住最內的圓圈時,也按住了紙上全部的同心圓,也按住了整張紙。因此單擊事件不單單發生在被擊中的元素上,換句話說,當咱們用鼠標單擊其中一個元素時,你也是在單擊元素的容器,甚至一層一層向外傳遞(也能夠是向內),甚至是在單擊整個頁面。css
定義:描述的是從頁面中接收事件的順序html
IE的事件流叫作事件冒泡,即事件開始時有最具體的元素(文檔中嵌套層次最深的那個節點)接收,而後逐級向上傳播到較爲不具體的節點,直到document對象。java
下圖展現了事件冒泡的過程瀏覽器
Netscape Communicator團隊提出的另外一種事件流叫作事件捕獲。事件捕獲的思想是不太具體的節點應該更早接收到事件,而最具體的節點應該最後接收到事件。
下圖展現了事件捕獲的過程函數
「DOM2級事件」規定的事件流包括三個階段:事件捕獲、處於目標階段和事件冒泡階段。發生的順序是事件捕獲階段==>目標階段==>事件冒泡階段測試
瞭解了基本概念,來用代碼測試一下。spa
html3d
<div id="first"> <div id="second"> <div id="third"></div> </div> </div>
css代理
#first{ width:200px; height:200px; margin:0 auto; background:red; border:1px solid #ccc; } #second{ width:150px; height:150px; margin:24px auto; background:yellow; border:1px solid #ccc; } #third{ width:100px; height:100px; margin:24px auto; background:blue; border:1px solid #ccc; }
js
//第三個參數設爲false,將事件處理程序添加到冒泡階段 first.addEventListener('click',function(e){ var target=e.target; console.log('紅色框'); },false); second.addEventListener('click',function(e){ var target=e.target; console.log('黃色框'); },false); third.addEventListener('click',function(e){ var target=e.target; console.log('藍色框'); },false);
單擊嵌套最深的元素,控制檯輸出結果:
由於最內層元素自己有一個單擊事件,它的父元素及祖先元素分別有一個單擊事件,因此單擊最內層元素位置,同時單擊了三個元素,啓動了三次事件處理程序。由於三個事件都是冒泡階段執行,因此控制檯輸出的順序爲最內層的藍色框——>中間的黃色框——>外層的紅色框。
將第三個參數都改成true,控制檯輸出以下:
這時事件執行順序改成從最外層的元素——>中間元素———>最內層的元素
咱們能夠很直觀的看到事件同時都在冒泡階段或捕獲階段執行的順序,但若是這三個元素的事件處理程序在不在同一階段執行呢?在看到結果以前能夠試試預想一下它們的執行順序。
咱們能夠試一試將紅色框與藍色框的第三個參數設爲false,黃色框的參數設爲true。輸出結果以下:
單擊藍色框後,開始事件捕獲階段:
從最外層的document對象(瀏覽器實際上是從window對象開始的)向內捕獲事件,路過紅色框時,查看到紅色框有事件,可是紅色框說:「我是在冒泡階段執行,如今是捕獲階段,等你回來再說吧。」接下來是黃色框:「我在捕獲階段執行,就是如今執行!在控制檯輸「黃色框」吧~~」
接下來到達目標階段:
「DOM2級事件」規範要求捕獲階段不會涉及事件目標即咱們點擊的那個最具體的元素,但IE九、Chrome等瀏覽器都會在捕獲階段觸發事件對象上的事件。執行目標對象的事件函數,控制檯輸出「藍色框」。
最後是冒泡階段:
由目標對象向外傳遞,到達黃色框,黃色框說:「我在捕獲階段執行過了,你走吧...」而後到達紅色框,紅色框說:「你終於回來了,如今就執行個人事件!」控制檯輸出「紅色框」。而後繼續向外傳播,直到到達document對象後中止。
其餘:更改了元素綁定事件代碼的順序,執行順序也和上面表現的一致。
將事件添加到什麼階段執行,事件就會在觸發事件後,在DOM事件流中相應的階段執行。
大多數狀況下,都是將事件處理程序添加到事件流的冒泡階段,這樣能夠最大程度的兼容各類瀏覽器(事件冒泡由IE提出),最好只在須要在事件到達目標以前截獲它的時候將事件處理程序添加到捕獲階段。
一個元素綁定事件時須要考慮到父元素及祖先元素的事件,應該注意它們之間的事件執行順序及執行結果,因此推薦在合適的狀況下使用事件代理。