簡單的說,事件流就是,確認觸發條件知足時,事件對應函數的調用順序。舉個例子,鼠標光標在某個按鈕上點擊了,按鈕又綁定了mousedown事件,那麼其對應的函數就會調用。而其實,光標落下的位置也在document、window的範圍內,或許還可能在其餘元素的盒模型內。若是這些元素也都綁定了mousedown事件,那麼哪一個元素的mousedown事件對應的函數先調用呢?這就須要確認一個發生的順序問題。html
具體的說,事件流分爲三個階段,即捕獲階段、目標(處理)階段、冒泡階段。網上隨便找了一張示意圖,以下:瀏覽器
其實這張圖以及網上不少說法(好比百度百科DOM事件流)都不是很嚴謹,漏掉了window對象。事件流應該是從window開始,在window對象結束(若是捕獲階段和冒泡階段,window都綁定了事件的話)。估計是window對象一般只在冒泡階段綁定load事件吧,不談也沒什麼影響。ide
下圖中,在鼠標單擊金黃色span區域時,控制檯對應打印出日誌。函數
源代碼在這裏:url
1 <!DOCTYPE html> 2 <html id="html"> 3 <head> 4 <meta charset="UTF-8"> 5 <title></title> 6 <style> 7 div{ 8 width: 200px; 9 height: 200px; 10 font-size: 30px; 11 color: #fff; 12 background: green; 13 } 14 span{ 15 display: block; 16 width: 100px; 17 height: 100px; 18 background: goldenrod; 19 color: #fff; 20 font-size: 30px; 21 } 22 body{ 23 border: 1px solid #000; 24 } 25 </style> 26 <script> 27 28 window.onload=function(){ 29 var div=document.getElementById("div"); 30 var span=document.getElementById("span"); 31 var html=document.getElementById("html"); 32 var body=document.getElementById("body"); 33 var head=document.getElementById("head"); 34 35 body.addEventListener('click',function(){console.log('body冒泡')},false); 36 html.addEventListener('click',function(){console.log('html冒泡')},false); 37 window.addEventListener('click',function(){console.log('window冒泡')},false); 38 document.addEventListener('click',function(){console.log('document冒泡')},false); 39 div.addEventListener('click',function(){console.log('div冒泡')},false); 40 span.addEventListener('click',function(){console.log('span冒泡')},false); 41 span.addEventListener('click',function(){console.log('span捕獲')},true); 42 document.addEventListener('click',function(){console.log('document捕獲')},true); 43 window.addEventListener('click',function(){console.log('window捕獲')},true); 44 html.addEventListener('click',function(){console.log('html捕獲')},true); 45 body.addEventListener('click',function(){console.log('body捕獲')},true); 46 div.addEventListener('click',function(){console.log('div捕獲')},true); 47 }; 48 </script> 49 </head> 50 <body id="body"> 51 <div id="div">div 52 <span id="span">span</span> 53 </div> 54 </body> 55 </html>
結合圖片和代碼,能夠發現兩個問題:spa
一、代碼中故意將打印帶有「冒泡」字樣的語句寫在了前面,並且也沒有按「window捕獲->document捕獲->html捕獲->body捕獲->div捕獲->span捕獲->span冒泡->div冒泡->body冒泡->html冒泡->document冒泡->window冒泡」這樣的順序,可是控制檯中打印的日誌基本上與事件流的順序一致。3d
二、第二個問題,也就是控制檯中打印的日誌與事件流的順序不一致的地方,爲何「span冒泡」在「span捕獲」前面呢?由於,觸發的是span綁定的事件,那麼span綁定的事件就在目標階段觸發。觸發順按照代碼中書寫順序來。本例中,即日誌
span.addEventListener('click',function(){console.log('span冒泡')},false); code
在htm
span.addEventListener('click',function(){console.log('span捕獲')},true); 前面。
注:
addEventListener綁定事件語法: 對象.addEventListener(事件名稱,事件綁定函數,布爾值)
布爾值取值說明:
* true 事件是在捕獲的階段發生的
* false 事件是在冒泡的階段發生的(缺省值)
說到事件流,通常都要說下阻止事件流。咱們知道能夠經過兩種方法綁定事件,一種是用on,一種是上面提到的addEventListener。針對綁定事件的方式不一樣,阻止事件流的方法也不一樣。
狀況1:
用on給元素綁定事件,全部的瀏覽器都是同樣的,先觸發事件源對象,而後再往外層元素冒泡。因此,只須要阻止冒泡就能夠了。將event對象身上的cancelBubble的值設爲true便可。
來看一個例子:
圖中,點擊box3後,box三、box2身上的事件會發生。而後,中止在box2,也就是不會在向外冒泡了。因此box1身上的事件沒有發生。
關鍵代碼以下:
1 box1.onclick=function(ev){ 2 console.log('box1點擊了'); 3 }; 4 box2.onclick=function(ev){ 5 console.log('box2點擊了'); 6 ev.cancelBubble=true; //這裏阻止了冒泡 7 }; 8 box3.onclick=function(ev){ 9 console.log('box3點擊了'); 10 };
狀況2:
用addEventListener綁定事件,可指定事件發生在捕獲階段仍是在冒泡階段。在事件函數內調用event身上的stopPropagation()方法,能夠阻止事件流繼續蔓延。
看一個具體的例子:
圖中,由於在冒泡階段box6綁定的事件函數內,阻止了事件流,點擊box6,事件流會在冒泡階段box6綁定的事件發生後中止。若是沒有阻止事件流,那麼控制檯中將會依次打印:捕獲階段box4點擊了->捕獲階段box5點擊了->捕獲階段box6點擊了->冒泡階段box4點擊了->冒泡階段box5點擊了->冒泡階段box6點擊了。
關鍵代碼以下:
1 box4.addEventListener('click',function(ev){ 2 console.log('捕獲階段box4點擊了'); 3 },true); 4 box5.addEventListener('click',function(ev){ 5 console.log('捕獲階段box5點擊了'); 6 },true); 7 box6.addEventListener('click',function(ev){ 8 console.log('捕獲階段box6點擊了'); 9 },true); 10 11 box4.addEventListener('click',function(ev){ 12 console.log('冒泡階段box4點擊了'); 13 }); 14 box5.addEventListener('click',function(ev){ 15 console.log('冒泡階段box5點擊了'); 16 }); 17 box6.addEventListener('click',function(ev){ 18 console.log('冒泡階段box6點擊了'); 19 ev.stopPropagation(); //由於在此處阻止了事件流蔓延,單擊box6的時候,只打印'冒泡階段box6點擊了'。不會波及到box5和box4。 20 });
本做品採用知識共享署名 4.0 國際許可協議進行許可。