js事件的捕獲和冒泡階段


討論的主要是兩個事件模型:IE事件模型與DOM事件模型

IE內核瀏覽器的事件模型是冒泡型事件(沒有捕獲事件過程),事件句柄的觸發順序是從ChildNode到ParentNode。 

 <div id="ancestor"> 

       <button id="child"> 

           Open the console and click me 

       </button> 

</div> 

 

以上的HTML代碼在IE內核下,事件是這樣傳播的:{

1、Button#child; 
2、div#ancestor; 
3、Body; 
4、Document 

 

DOM標准的瀏覽器事件是:捕獲事件和冒泡事件。

捕獲事件過程:{

1、Window 
2、Document 
3、Body 
4、Div#ancestor 
5、Button#child 

}

冒泡事件過程:{

6、Div#ancestor 
7、Body 
8、Document 
9、Window 

}

當開發者在一個元素上注冊了事件后,這個事件的響應順序是從window(最頂層)開始一級一級的向下傳播,然后到了該元素后事件捕獲過程結束,事件開如冒泡,一級一級向父層元素冒泡(請注意第6步)。

當然,開發者可以很輕松的決定DOM標准的瀏覽器中的事件需要在哪個傳播過程觸發。

 

事件的注冊機制:

DOM標准的瀏覽器事件注冊方法是通過addEventListener方法注冊,而IE內核的瀏覽器則是通過attachEvent方法注冊。 
這兩個方法的區別:
addEventListener方法帶有三個參數,分別是:eventType、handler、useCapture。 
eventType不帶有on字符串; 
handler參數是一個事件句柄,這個函數或方法帶有一個事件對象參數; 
useCapture參數決定了事件句柄觸發在哪種事件傳播階段,如果useCapture為true則為捕獲階段,反之則為冒泡階段。 

 

繼續看演示: 

var ancestorHandler = function (e){ 

//...... 

 }, 

 childHandler = function (e){ 

//...... 

}; 

 document.querySelector('#ancestor').addEventListener('click',ancestorHandler,false);//注意第三個參數 ,注冊了一個在冒泡階段觸發的事件句柄

 document.querySelector('#child').addEventListener('click',childHandler,true);//注意第三個參數 ,注冊了一個在捕獲階段的事件句柄

 

 
當用戶在這個DIV元素上點擊時,事件的執行順序是childHandler、ancestorHandler。 

原因:按鈕的事件是在捕獲階段觸發的,也就是從上到下,而DIV的事件是注冊在冒泡階段,也就是點擊了這個按鈕開始從這個按鈕的位置往上冒泡。

 

阻止事件的冒泡:

DOM事件對象提供了stopPropagation方法用於阻止事件流。 

var ancestorHandler = function (e){ 
  //...... 
}, 
childHandler = function (e){ 
  e.stopPropagation(); 
  //...... 
}; 


以上代碼在childHandler函數中添加了e.stopPropagation()代碼片段,它將阻止事件流,事件流包括捕獲階段及冒泡階段的事件流。 

 

再修改上面的代碼如下: 

var ancestorHandler = function (e){ 
  //...... 
}, 
childHandler = function (e){ 
  //...... 
}; 
document.querySelector('#ancestor').addEventListener('click',ancestorHandler,true);//注意第三個參數 
document.querySelector('#child').addEventListener('click',childHandler,true);//注意第三個參數 


以上的代碼產生的結果是:用戶在DIV元素上單擊時,將會依次觸發ancestorHandler、childHandler函數,為什么?因為我們將div#ancestor的事件注冊到捕獲階段了,也就是從上至下。當然了我們還可以阻止childHandler方法的執行。

以上代碼將阻止按鈕的事件觸發。當用戶點擊了DIV的區域,僅僅觸發ancestorHandler函數,因為阻止了事件流。 

 

IE內核的瀏覽器中是如何注冊事件的。IE內核提供了attachEvent方法為元素注冊事件,注意該方法與DOM的addEventListener方法區別很大!該方法帶有兩個參數:

{

eventType 事件類型,請注意這個參數與addEventListener的eventType的區別,它必須帶有on; 

handler 事件句柄 ,請注意attachEvent沒有提供事件捕獲階段的參數,IE內核的事件都是發生在冒泡階段! 

}

var ancestorHandler = function (e){ 
  //...... 
}, 
childHandler = function (e){ 
  //...... 
}; 
document.getElementById('ancestor').attachEvent('onclick',ancestorHandler);//注意沒有第三個參數 
document.getElementById('child').attachEvent('onclick',childHandler);//注意沒有第三個參數 


以上代碼在IE中將為DIV元素和按鈕元素注冊了不同的事件。 

 

另外還有一些注意事項: 

1、DOM標准的addEventListener方法執行事件的順序是按照事件注冊的順序執行的。而attachEvent方法則相反–后注冊的事件先觖發,先注冊的事件后觸發。 
2、DOM標准的瀏覽器文本節點也會冒泡,而IE內核的瀏覽器文本節點不會冒泡。 
3、DOM標准的瀏覽器事件對象與IE內核的瀏覽器事件不同(具體請參閱http://www.quirksmode.org/js/introevents.html)。 
4、DOM標准的瀏覽器事件卸載方式與IE內核的事件卸載方式不同。 
1 object.removeEventListener(eventType,handler,useCapture);//DOM標准的事件卸載方式 
2 object.detachEvent(eventType,handler);//IE內核的事件卸載方式 

在DOM標准的事件卸載方式中需要注意的是:事件捕獲的參數。如果你的事件是注冊在捕獲階段,則卸載事件時,必須將其指定為捕獲階段(true),否則無法卸載;如果你的事件注冊在注冊在冒泡階段,則必須將其指定為冒泡階段(false),否則同樣無法卸載!

                          寫作不易,難免有疏漏和錯誤,還請慷慨指正,不錯請推薦


                                      每天多學一點點     代碼少敲一點點 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM