跳轉到

瀏覽器 js 事件流

在JavaScript 中,事件觸發過程涉及兩個主要機制:事件捕獲(Event Capturing)和事件冒泡(Event Bubbling),這兩個機制的默認順序是事件冒泡,但我們也可以透過呼叫事件物件的方法來切換到事件捕獲模式。

範例程式碼:

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>Document</title>
</head>
<style>
 *{
 margin: 0;
 padding: 0;
 }
 #a{
 width: 400px;
 height: 400px;
 background-color: #b92929;
 }
 #b{
 width: 200px;
 height: 200px;
 background-color: #1caa55;
 }
 #c{
 width: 100px;
 height: 100px;
 background-color: #000000;
 }
</style>
<body>
 <div id="a">
 <div id="b">
 <div id="c">
 </div>
 </div>
 </div>
</body>
<script>
 let a = document.getElementById("a");
 let b = document.getElementById("b");
 let c = document.getElementById("c");
 a.addEventListener("click",function(){
 console.log("點擊a");
 },true)
 b.addEventListener("click",function(){
 console.log("點擊b");
 },true)
 c.addEventListener("click",function(){
 console.log("點擊c");
 },true)
</script>
</html>

事件捕獲機制

概念:在事件觸發的過程中,瀏覽器先從文件根元素開始往裡面尋找目標元素,這個過程稱為事件擷取。透過事件捕獲,可以在事件到達目標元素之前捕獲到事件,並執行相應的處理函數。

在上面程式碼中,我們將監聽事件的第三個參數設為true,這樣我們就可以切換到事件擷取模式,當我們點擊c時,瀏覽器從根元素開始向裡面開始尋找目標元素,然後在這個過程中依序捕獲了點擊事件a,點擊事件b,最後才找到目標元素c,捕獲到點擊事件c,所以會依序列印點擊a 點擊b 點擊c

事件冒泡機制

概念:一旦事件到達目標元素並執行對應的處理函數後,它會開始在目標元素上方的父元素中冒泡,直到到達文檔根元素。這個過程稱為事件冒泡。透過事件冒泡,可以在事件冒泡階段捕獲到事件,並執行對應的處理函數。

我們不做任何設定時(沒有設定監聽事件的第三個參數),預設就是冒泡機制,也很好理解,其實就是和捕獲機制相反的一個過程,就好比你往牆上丟了一個球,這個球會反彈回來,這個球往牆上飛的過程就是事件的捕捉過程,而球彈回來的過程就是冒泡的過程。我們點擊c,瀏覽器找到目標元素時,就會向外層的父級元素冒泡,所以在這個範例中,我們依序會執行點擊事件c、點擊事件b、點擊事件a,列印結果:點擊c 點擊b 點擊a

stopPropagation 和stopImmediatePropagation

那如果我們不希望事件繼續傳播,還是這個例子,假設在預設情況下,我們點擊了c,然後只想列印c而不希望觸發點擊事件b和點擊事件a,那我們該怎麼做呢

在Javascript有兩個常用的方法:

stopPropagation()stopImmediatePropagation()都是用來阻止事件進一步傳播的方法,但它們在功能和作用上有一些不同。

  1. stopPropagation()stopPropagation()方法用於阻止事件的冒泡或捕獲過程。當我們呼叫stopPropagation()方法時,事件將停止在目前元素上觸發其他相同類型的事件處理函數,並停止繼續向上或向下傳播到其他元素。這意味著其他父級或子級元素上的此類的事件處理函數將不會被觸發。但如果當前元素上綁定了多個相同類型的事件處理函數,除了目前正在執行的處理函數外,其他處理函數仍然會被執行。如下: 只會列印點擊c和點擊d
 a.addEventListener("click",function(){
 console.log("點擊a");
 })
 b.addEventListener("click",function(){
 console.log("點擊b");
 })
 c.addEventListener("click",function(e){
 e.stopPropagation()
 console.log("點擊c");
 })
 c.addEventListener("click",function(e){
 console.log("點擊d");
 }) 
  1. stopImmediatePropagation()stopImmediatePropagation()方法也用來阻止事件的傳播,但它的角色更為強大。當您呼叫stopImmediatePropagation()方法時,事件將立即停止,並且不會再觸發當前元素上剩餘的任何相同類型的事件處理函數,也不會繼續傳播到其他元素。這包括目前元素上綁定的其他事件處理函數,以及同級元素上的事件處理函數。換句話說,除了目前正在執行的處理函數外,其他任何處理函數都不會被執行。

如下只會列印點擊c

a.addEventListener("click",function(){
 console.log("點擊a");
 })
 b.addEventListener("click",function(){
 console.log("點擊b");
 })
 c.addEventListener("click",function(e){
 e.stopImmediatePropagation()
 console.log("點擊c");
 })
 c.addEventListener("click",function(e){
 console.log("點擊d");
 })`