事件冒泡与捕获

171 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情

事件冒泡与捕获

什么叫事件冒泡与事件捕获?

事件冒泡与事件委托都是为了解决页面的事件流,也就是事件的发生顺序而产出的,其中事件冒泡是微软公司提出来的,事件捕获是网景公司提出来的。事件捕获是当事件流从顶部向下传递时,遇到目标元素就会触发事件,可以想象成从金字塔顶端向下,金字塔的顶端就是document元素,而事件冒泡是当事件流从底部向上传递的时候,遇到目标元素触发对应事件,事件冒泡可以想象成从水底向上冒泡,而水底就是目标元素,水面就是document元素。

例子:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <style>
    .father {
      width: 500px;
      height: 500px;
      background-color: #ccc;
    }

    .son {
      width: 300px;
      height: 300px;
      background-color: skyblue;
    }
  </style>
  <body>
    <div class="father">
      <div class="son"></div>
    </div>
    <script src="./index.js"></script>
  </body>
</html>
// 获取Dom元素

const father = document.querySelector(".father");
const son = document.querySelector(".son");

// 给父元素添加点击事件

father.addEventListener("click", () => {
  console.log("father被点击了");
});

son.addEventListener("click", () => {
  console.log("son被点击了");
});

根据上面的代码,我们来页面上尝试一下效果 tfnMQ.png

灰色的盒子是父盒子,蓝色的盒子是子盒子,我们在两个盒子上面都添加了点击事件,当我们点击父盒子的时候控制台会输出father被点击了,当我们点击子盒子的时候,控制台会输出son被点击了father被点击了。这可以看出,通过addEventListener添加的事件默认的事件流处理方式是事件冒泡。

接下来我们改变一下事件流的处理方式,我们改成事件捕获。我们只需要将addEventListener的第三个参数变成 true 就好了。

// 获取Dom元素

const father = document.querySelector(".father");
const son = document.querySelector(".son");

// 给父元素添加点击事件

father.addEventListener(
  "click",
  () => {
    console.log("father被点击了");
  },
  true
);

son.addEventListener(
  "click",
  () => {
    console.log("son被点击了");
  },
  true
);

还是刚刚的页面,我们现在来看看控制台的输出 tfVbB.png

事件冒泡与事件捕获之间的关系与区别

  • 关系 事件冒泡与事件捕获都是为了处理页面的事件流而产生的两种不同的解决方法,它门的顶层元素都是document
  • 区别 事件冒泡是从目标元素向上冒泡,直到遇到document对象,而事件捕获是从document对象向下寻找目标元素,直到找到目标元素。触发事件。

tfjyT.jpg

事件委托

事件委托的原理是借助事件冒泡的特性,从目标元素向上冒泡,当我们需要为多个标签绑定同一个事件的时候,例如:多个li标签绑定点击事件,那么我们就可以使用事件委托来实现。当我们需要实现点击每个li标签都触发对应的事件的时候,我们可以在其父标签ul上绑定对应的点击事件,然后当我们点击li标签的时候,事件流会向上冒泡,于是就到了ul这里,接着就会触发ul的事件。事件委托的好处是可以减少内存的使用,降低频繁的操作 Dom,减少重排与重绘,提高页面的性能。

例子:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <style></style>
  <body>
    <ul class="ul">
      <li>1</li>
      <li>2</li>
      <li>3</li>
      <li>4</li>
      <li>5</li>
    </ul>
    <script src="./index.js"></script>
  </body>
</html>
// 获取Dom元素

const ul = document.querySelector(".ul");

// 给父元素添加点击事件
ul.addEventListener("click", (event) => {
  //通过event对象获取点击的子元素
  console.log(event.target.innerHTML);
});

通过上面的代码,当我们在页面点击li元素的时候,我们就会获取到点击的元素的内容,这就是事件委托的好处。 tfvl2.png

总结

事件冒泡与事件捕获都有各自的使用场景,我们要结合开发实际来选择对应的事件处理方式。当前我们使用addEventListener为元素添加事件的时候,默认的事件流处理方式是事件冒泡,而想要更改事件流处理方式,可以给addEventListener添加第三个参数true。 详细资料可查看 事件流 javascript Event order