在 HTML 中,当事件发生时,会执行相应的事件处理函数。事件处理函数会被添加到元素的事件监听器中,以便在事件触发时被执行。
当事件被触发时,事件的传递过程从最底层的元素(即事件源)开始,逐级向上传递,直到传递到 document 对象为止。在这个过程中,事件会经过三个阶段:捕获阶段、目标阶段和冒泡阶段。
-
捕获阶段(Capture Phase):从 document 对象开始,逐级向下传递,直到事件源元素。在捕获阶段,事件处理函数会按照由外向内(由父元素到子元素)的顺序被依次执行。
-
目标阶段(Target Phase):当事件传递到事件源元素时,就进入了目标阶段。在目标阶段,事件处理函数会被执行,此时可以通过
event.target
属性获取到具体触发事件的元素。 -
冒泡阶段(Bubble Phase):从事件源元素开始,逐级向上传递,直到 document 对象。在冒泡阶段,事件处理函数会按照由内向外(由子元素到父元素)的顺序被依次执行。
事件传递过程中,如果事件处理函数调用了 event.stopPropagation()
方法,就可以停止事件传递。在这种情况下,事件不会在继续向上传递,并且不会触发其他元素上的相同类型的事件。
总结来说,HTML 事件传递的过程是一个由外向内再由内向外的过程,同时允许在特定的阶段阻止事件的传递和默认的行为。
在捕获阶段中,可以通过 addEventListener()
函数的第三个参数(选项)设置 capture
选项来监听事件的捕获阶段。但是在捕获阶段中是无法阻止事件向下传递的,因为事件是从整个文档树上一次性自顶向下传递到初始目标的。
但是,我们可以在冒泡阶段中通过 event.stopPropagation()
方法来停止事件的传递。这样,事件就不会在继续向上传递
以下是一个例子,演示了如何在冒泡阶段中停止事件传递:
<!DOCTYPE html>
<html>
<head>
<title>Stop Event in Capture Phase</title>
</head>
<body>
<div>
<p>Click Me!</p>
</div>
<script>
const div = document.querySelector("div");
const p = document.querySelector("p");
div.addEventListener("click", function () {
console.log("Div Clicked (capture)");
}, true);
p.addEventListener("click", function (event) {
console.log("Paragraph Clicked (capture)");
event.stopPropagation();
}, true);
div.addEventListener("click", function () {
console.log("Div Clicked (bubble)");
}, false);
</script>
</body>
</html>
在上面的代码中,我们在 div
元素和 p
元素上都添加了一个 click
事件的捕获阶段监听器。当点击 p
元素时,会触发 p
元素的捕获监听器,并立即停止事件传递,因此在点击 div
元素时,只会触发 div
元素的捕获监听器,而不会触发它的冒泡监听器。
在捕获阶段中,确实无法阻止事件向下传递。
当在事件传递过程中某个元素处于捕获阶段时,该元素上注册的捕获事件处理函数会被调用,不过这些事件处理函数无法阻止事件为事件目标元素创造的事件流和默认行为。这是因为事件流是一个单向的传递过程,如果在捕获阶段中停止了事件传递,那么接下来就不会进入目标阶段,更别提冒泡阶段了。
如果要阻止事件的传播,应该在事件传递到目标元素后再停止事件的传递。这样可以保证事件的默认流程正常进行,同时又可以避免其他元素上的相同类型的事件触发。