JavaScript 基础:事件传播
很多开发者经常会对 DOM 中的事件流感到疑惑,当我们在一个元素上点击的时候,目标元素的父元素的事件也会被触发,反之亦然。
我已经遇到这个问题很多次了,这是在 JavaScript 开发中的主要概念之一,也经常在 JavaScript 相关的面试中出现。
事件传播描述了事件及其传播的方向。这篇文章,将讨论两个主要事件传播相关的技术,它们分别是:
事件冒泡
在这种事件传播中,一系列事件在 DOM 中由内向外传播。在上图中,DOM 中一共有 3 个 div
(子、中、父)。如果我们在子 div
上点击,子 div
被点击后,紧接着,中 div
和父 div
也会被点击。
通过将点击事件和气泡进行类比可以帮助我们更好地理解它,因为气泡具有向外冒的特性,因此我们把这种事件向外传播的行为称为「事件冒泡」。
上图中,黄色的箭头指明了事件冒泡中事件传播的方向。
事件捕获
在这种事件传播中,事件在 DOM 中由外向内传播。因此,当我们点击子 div
的时候,第一个事件将在父 div
被调用,然后是中 div
和子 div
。事件捕获的顺序由上图中的蓝色箭头表示,它由父 div
指向中 div
,然后再指向子 div
。当执行任何事件的时候,我们有两种类型的配置,可以通过浏览器指定我们想要使用的类型,由 addEventListener()
方法中的 useCapture
参数来指定。
document.querySelector("child").
addEventListener('click' , (evt) => {
console.log("child Clicked");
}, true) // 启用事件捕获
document.querySelector("child").
addEventListener('click' , (evt) => {
console.log("child Clicked");
}, false) // 启用事件冒泡
addEventListener()
方法包含三个参数,分别是 event
、callback method
和 useCapture
。useCapture
参数指定浏览器使用哪种类型的事件传播。如果将它的值设置为 true
,浏览器会启用事件捕获。如果没有指定或指定为 false
,则浏览器会默认启用事件冒泡。
当我们不需要任何传播周期时,事件传播是一个非常昂贵的操作。当一个事件有多个处理程序时,它非常有用,否则,我们可以禁用事件传播。
我们可以通过以下方式禁用事件传播:
- event.stopPropagation(): 这个方法会终止指定的事件进一步传播到他的父元素或者子元素,只调用目标元素的事件处理程序。
- event.stopImmediatePropagation(): 这个方法不仅可以终止事件进一步传播,还会阻止目标事件的其它处理程序的执行。
- event.preventDefault(): 这个方法将会限制事件的默认操作的执行。如果事件可以被取消,只需要简单地调用
preventDefault()
方法即可。例如,当点击一个提交按钮时想阻止表单的提交,这个方法很有用。
addEventListener('click', (evt) => {
evt.stopPropagation(); // 只终止事件进一步传播
}, false)
addEventListener('click', (evt) => {
evt.stopImmediatePropagation();
//终止事件的进一步传播,并阻止目标事件的其它处理程序的执行
}, false)
addEventListener('click', (evt) => {
evt.preventDefault(); // 限制默认操作的执行
}, false)
任何事件处理程序都可以通过调用 event.stopPropagation()
方法来终止这个事件,但是并不推荐这样做,因为我们并不是真的确定是不是需要这样。
这在事件捕获中很少使用,但是我们通常在事件冒泡中这样做,这背后的逻辑是:在现实世界中,当一个事件发生时,地方当局会首先做出反应,它们最了解事发当地的情况,如果需要,它们会汇报给更高级别的当局。
在下面的评论中,告诉我你对使用事件传播有什么看法。