平時瀏覽這么多技術文章,如過不去實踐、深入弄透它,這個技術點很快就會在腦海里模糊。要加深印象,就得好好過一遍。重要的事情說三遍,重要的知識寫一遍。
開發過程中我們都希望使用別人成熟的框架,因為站在巨人的肩膀上會使得我們開發的效率大幅度提升。不過,我們也應該、必須了解其基本原理。比如DOM事件,jquery框架幫我們為我們封裝和抽象了各瀏覽器的差異行為,為事件處理帶來了極大的便利。不過瀏覽器逐步走向統一和標准化,我們可以更加安全地使用官方規范的接口。因為只有獲得眾多開發者的芳心,瀏覽器才會走得更遠。正如我們現在使用低版本瀏覽器打開某些頁面時,會告知我們要用chrome等高級瀏覽器訪問。不過這是一個革命的過程,為了讓我們的webPage更好地服務更多的人,現在我們還不得不對這些歷史遺留問題做更好的兼容。要做好兼容,除了依賴框架,我們得理解其基本原理。
DOM事件三個階段
當一個DOM事件被觸發時,它不僅僅只是單純地在本身對象上觸發一次,而是會經歷三個不同的階段:

- 捕獲階段:先由文檔的根節點document往事件觸發對象,從外向內捕獲事件對象;
- 目標階段:到達目標事件位置(事發地),觸發事件;
- 冒泡階段:再從目標事件位置往文檔的根節點方向回溯,從內向外冒泡事件對象。

引用來源:http://www.w3.org/TR/DOM-Level-3-Events/#event-flow
事件捕獲與事件冒泡先后執行順序就顯而易見了。
實驗部分
打開在線編輯器:http://jsbin.com/goqede/edit?html,css,js,output
代碼如下:
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Document</title> 6 <style> 7 #outer{ 8 text-align: center; 9 width: 400px; 10 height: 400px; 11 background-color: #ccc; 12 margin: 0 auto; 13 } 14 #middle{ 15 width: 250px; 16 height: 250px; 17 background-color: #f00; 18 margin: 0 auto; 19 } 20 #inner{ 21 width: 100px; 22 height: 100px; 23 background-color: #0f0; 24 margin: 0 auto; 25 border-rad 26 } 27 </style> 28 </head> 29 <body> 30 <div id='outer'> 31 <span>outer</span> 32 <div id='middle'> 33 <span>middle</span> 34 <div id='inner'> 35 <span>inner</span> 36 </div> 37 </div> 38 </div> 39 <script> 40 function $(element){ 41 return document.getElementById(element); 42 } 43 function on(element,event_name,handler,use_capture){ 44 if(addEventListener){ 45 $(element).addEventListener(event_name,handler,use_capture); 46 } 47 else{ 48 $(element).attachEvent('on'+event_name,handler); 49 } 50 } 51 52 on("outer","click",o_click_c,true); 53 on("middle","click",m_click_c,true); 54 on("inner","click",i_click_c,true); 55 56 on("outer","click",o_click_b,false); 57 on("middle","click",m_click_b,false); 58 on("inner","click",i_click_b,false); 59 60 61 62 function o_click_c(){ 63 console.log("outer_捕獲"); 64 alert("outer_捕獲"); 65 } 66 function m_click_c(){ 67 console.log("middle_捕獲") 68 alert("middle_捕獲"); 69 } 70 function i_click_c(){ 71 console.log("inner_捕獲") 72 alert("inner_捕獲"); 73 } 74 function o_click_b(){ 75 console.log("outer_冒泡") 76 alert("outer_冒泡"); 77 } 78 function m_click_b(){ 79 console.log("middle_冒泡") 80 alert("middle_冒泡"); 81 } 82 function i_click_b(){ 83 console.log("inner_冒泡") 84 alert("inner_冒泡"); 85 } 86 </script> 87 </body> 88 </html>
當我們點擊inner的時候結果是:

outer_捕獲
middle_捕獲
inner_捕獲
inner_冒泡
middle_冒泡
outer_冒泡
由此可見:確實是先由外向內事件捕獲,一直到事發元素,在由內向外冒泡到根節點上
tips:
當事件觸發在目標階段時,會根據事件注冊的先后順序執行,在其他兩個階段注冊順序不影響事件執行順序。也就是說如果該處既注冊了冒泡事件,也注冊了捕獲事件,則按照注冊順序執行。

例如當我點擊inner的時候,按照以上順序,答案確實是我們想要的答案:
、
當我的事件注冊順序改變成如下代碼時:

當我們點擊outer時:

當我們點擊middle時:

當我們點擊inner時:

可以看出在目標階段的事發元素上的事件執行順序是有事件注冊順序決定的
