在js中存在事件冒泡與事件捕獲兩種概念,這兩個概念都是為了解決頁面中事件流(事件發生順序)的問題。

事件冒泡(dubbed bubbling)
事件冒泡我們從字面意思理解就是當用戶行為觸發我們頁面的定義好的事件后,會有一個由內到外的一個冒泡過程,而不是一下子就命中事件綁定的元素
事件捕獲(event capturing)
事件捕獲與冒泡恰恰相反,當鼠標點擊或者觸發dom事件時,瀏覽器會從根節點開始由外到內進行事件傳播,即點擊了子元素,如果父元素通過事件捕獲方式注冊了對應的事件的話,會先觸發父元素綁定的事件
我們用代碼來理解一下
在下邊這個例子中,如果兩個元素都有一個click的處理函數,那么我們怎么才能知道哪一個函數會首先被觸發呢?為了解決這種腦殼痛的問題,就有了今天的主題冒泡與捕獲
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>JS事件處理程序</title>
<link href="https://cdn.bootcss.com/skeleton/2.0.4/skeleton.min.css" rel="stylesheet">
</head>
<body>
<div class="wrapper" id="wrapper">
<div class="container">
<button id="event">JS事件處理程序</button>
</div>
</div>
<script>
var wrapper = document.getElementById("wrapper"),
event = document.getElementById("event");
wrapper.addEventListener("click", function () {
alert("1");
console.log("1");
}, true)
event.addEventListener("click", function () {
alert("2");
console.log("2");
}, true)
wrapper.addEventListener("click", function () {
alert("3");
console.log("3");
}, false)
event.addEventListener("click", function () {
alert("4");
console.log("4");
}, false)
</script>
</body>
</html>
上面的代碼最終輸出結果為:
-
1
-
2
-
4
-
3
在DOM2級事件規定的時間流包括 三個階段:
-
事件捕獲階段
-
處於目標階段
-
事件冒泡階段
我們可以看到addEventListener的第三個參數我們傳入的不同,也就是上面結果為什么沒有順序執行的原因,這里我們在來回顧一下addEventListener
addEventListener
語法: target.addEventListener(type, listener[, useCapture])
useCapture 可選Boolean, 當useCapture為true 事件句柄在捕獲階段執行,也就是事件由外向內執行 當useCapture為false 事件句柄在冒泡階段執行,也就是事件由內向外執行
看到這也應該了解上面代碼為何會輸出1243了
好了,回來業務中,實際應用場景我們肯定不願同時觸發多個click, 在點擊子元素時我們不想觸發父元素的事, 這個時候我們就可以使用stopPropagation來停止事件冒泡
代碼理解
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>JS事件處理程序</title>
<link href="https://cdn.bootcss.com/skeleton/2.0.4/skeleton.min.css" rel="stylesheet">
</head>
<body>
<div class="wrapper" id="wrapper">
<div class="container">
<button id="event">JS事件處理程序</button>
</div>
</div>
<script>
var wrapper = document.getElementById("wrapper"),
event = document.getElementById("event");
wrapper.onclick = function () {
console.log('捕獲階段執行父元素wrapper的事件處理程序')
}
event.onclick = function () {
// 阻止事件冒泡
e.stopPropagation()
console.log('冒泡階段執行子元素event的事件處理程序')
}
</script>
</body>
</html>
上面的示例中我們使用了stopPropagation來阻止冒泡,所以此時只會觸發一個事件了
總結
-
事件冒泡由內向外執行
-
事件傳播由外向內執行
-
addEventListener的第三個參數可以改變事件流的狀態
-
使用stopPropagation可以阻止冒泡
