1. 程式人生 > 實用技巧 >73.如何阻止預設事件?

73.如何阻止預設事件?

在JS中經常需要阻止元素的預設事件。而阻止預設事件的方法都是使用事件物件的preventDefault()方法或者在函式中return false。在最近一次開發中使用preventDefault()方法的時候遇到一個問題,現在才想/猜明白原因,場景是這樣的:

<a href="https://www.csdn.net" target="_blank"><p>點我跳轉</p></a>
document.querySelector('p').addEventListener('click', function (ev) {
  ev.preventDefault()
})
document.querySelector('a').addEventListener('click', function (ev) {
  console.log('事件冒泡到a標籤')
})

結果是連結沒有跳轉。當時覺得莫名其妙,阻止預設事件是在點選p元素時候阻止的,也只是阻止了預設事件,並沒有阻止事件冒泡,事件還是冒泡到了a元素,但是卻沒有觸發a元素跳轉,就像在a元素上阻止了預設事件一樣。

要理解這個現象首先要知道在p元素和a元素的click事件處理函式中捕獲的ev物件是同一個物件。

注:如果監聽的事件不同捕獲的事件物件自然不同。

修改上面的指令碼如下:

var eve = null
document.querySelector('p').addEventListener('click', function (ev) {
  eve = ev
})
document.querySelector('a').addEventListener('click', function (ev) {
  console.log(eve === ev)  // 可以看出來輸出了 true
})

所以在事件冒泡過程中只要有一個處理函式阻止了預設事件,那麼當事件冒泡到祖先元素的時候也是被阻止了預設事件的事件物件。

還可以通過事件物件上的一個屬性defaultPrevented看出來這個事件物件執行過preventDefault()方法。

document.querySelector('p').addEventListener('click', function (ev) {
  console.log('執行之前', ev.defaultPrevented) // 輸出false
  ev.preventDefault()
  console.log('執行之後', ev.defaultPrevented) // 輸出true
})
document.querySelector('a').addEventListener('click', function (ev) {
  console.log(ev.defaultPrevented) // 輸入 true
})

事件傳遞過程

高程上介紹事件的一章中介紹到,事件傳播分為三個階段,首先是捕獲,然後是處於目標,然後是冒泡。

在目標元素上繫結事件會發現,addEventListener第三個引數為true繫結的函式並不會在為false繫結的函式之前執行,而執行順序只會和繫結順序有關。

所以為什麼在事件處理函式中列印事件物件的currentTarget屬性在控制檯看不到值呢?因為當我們在控制檯看的時候事件物件已經不是事件處理函式console.log那一刻的物件了,在向上冒泡的過程中被修改了。