天天看點

addeventlistener事件第三個參數_JS DOM 事件流、事件冒泡

addeventlistener事件第三個參數_JS DOM 事件流、事件冒泡
當一個HTML元素觸發一個事件時,該事件會在元素結點與根結點之間的路徑傳播。傳播按順序分為三個階段:捕獲階段、目标階段、冒泡階段,這個傳播過程就是 DOM 事件流。 事件冒泡就是當一個HTML元素出發一個事件時,它的祖先節點都會收到該事件。
  • 通過設定

    addEventListener

    的第三個參數可以決定事件是否在捕獲階段觸發。
  • 通過

    event.stopPropagation()

    可以阻止事件冒泡。

一、定義

DOM結構是一個樹型結構,當一個HTML元素觸發一個事件時,該事件會在元素結點與根結點之間的路徑傳播,路徑所經過的結點都會收到該事件,這個傳播過程可稱為 DOM 事件流(DOM event flow )。

點選檢視W3C對事件流的定義,裡面有事件在dom樹上傳播過程的圖檔。

傳播(Propagation)按順序分三個階段(Any event taking place in the W3C event model is first captured until it reaches the target element and then bubbles up again):

  1. 捕獲階段(capture phrase,從根節點window到目标節點,即最近的、最精确的元素節點)
  2. 目标階段(target phrase,目标節點上的事件觸發按代碼執行順序觸發)
  3. 冒泡階段(bubbling phrase,從目标節點到根節點 )

二、示範

<div>
  <button>點選</button>
</div>
           

現在有一個div節點,div節點裡面有一個button節點。

let div = document.getElementsByTagName('div')[0];
div.addEventListener('click',(e)=>{
  console.log('div')
})
let button = document.getElementsByTagName('button')[0];
button.addEventListener('click',(e)=>{
  console.log('button')
})
           

現在我們隻看

div

節點和

button

節點,當我們點選

button

時會先後列印出

button

div

,因為

addEventListener

方法預設是讓事件在冒泡階段觸發。如果我們設定

addEventListener

第三個參數

useCapture

的值為

true

,就會讓事件在捕獲階段觸發:

div.addEventListener('click',(e)=>{
  console.log('div')
},true)
           

或者

div.addEventListener('click',(e)=>{
  console.log('div')
},{capture: true})
           

這個時候點選

button

就會先觸發

div

click

事件,再觸發

button

click

事件。

三、停止傳播:event.stopPropagation()

stopPropagation

方法會讓事件傳播到目标階段後停止傳播,是以也叫阻止冒泡。相當于讓事件流隻剩下捕獲階段和目标階段。是以下面的代碼會先後列印出

div1

button

button.addEventListener('click',(e)=>{
  e.stopPropagation()
  console.log('button')
})
div.addEventListener('click',(e)=>{
  console.log('div1')
},true)
div.addEventListener('click',(e)=>{
  console.log('div2')
})
           

四、馬上停止傳播:event.stopImmediatePropagation();

有個特例,如果目标階段的節點綁定了多個事件,它們不會區分捕獲和冒泡,事件觸發的順序為代碼執行的順序。

而且

event.stopPropagation()

在目标階段不會生效。如果目标階段有 a、b、c 三個觸發事件會按序執行,在 b 事件裡設定

event.stopPropagation()

并不會影響 c 事件的觸發。 但是如果在 b 事件裡設定

event.stopImmediatePropagation()

後 ,事件觸發到b之後就會停止觸發後面的所有事件。

更多關于DOM事件模型,推薦看阮一峰的教程

繼續閱讀