JavaScript 基础:事件传播

147 阅读3分钟

JavaScript 基础:事件传播

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() 方法包含三个参数,分别是 eventcallback methoduseCaptureuseCapture 参数指定浏览器使用哪种类型的事件传播。如果将它的值设置为 true,浏览器会启用事件捕获。如果没有指定或指定为 false,则浏览器会默认启用事件冒泡。

当我们不需要任何传播周期时,事件传播是一个非常昂贵的操作。当一个事件有多个处理程序时,它非常有用,否则,我们可以禁用事件传播。

我们可以通过以下方式禁用事件传播:

  1. event.stopPropagation(): 这个方法会终止指定的事件进一步传播到他的父元素或者子元素,只调用目标元素的事件处理程序。
  2. event.stopImmediatePropagation(): 这个方法不仅可以终止事件进一步传播,还会阻止目标事件的其它处理程序的执行。
  3. event.preventDefault(): 这个方法将会限制事件的默认操作的执行。如果事件可以被取消,只需要简单地调用 preventDefault() 方法即可。例如,当点击一个提交按钮时想阻止表单的提交,这个方法很有用。
addEventListener('click', (evt) => {
	evt.stopPropagation(); // 只终止事件进一步传播
}, false)

addEventListener('click', (evt) => {
	evt.stopImmediatePropagation(); 
	//终止事件的进一步传播,并阻止目标事件的其它处理程序的执行
}, false)

addEventListener('click', (evt) => {
	evt.preventDefault(); // 限制默认操作的执行
}, false)

任何事件处理程序都可以通过调用 event.stopPropagation() 方法来终止这个事件,但是并不推荐这样做,因为我们并不是真的确定是不是需要这样。

这在事件捕获中很少使用,但是我们通常在事件冒泡中这样做,这背后的逻辑是:在现实世界中,当一个事件发生时,地方当局会首先做出反应,它们最了解事发当地的情况,如果需要,它们会汇报给更高级别的当局。

在下面的评论中,告诉我你对使用事件传播有什么看法。