js事件冒泡、事件捕获、事件委托

59 阅读2分钟

首先我们要知道,DOM事件流存在三个阶段:事件捕获阶段,处于目标阶段,事件冒泡阶段 DOM标准事件流的触发的先后顺序是:先捕获再冒泡

addEventListener的第三个参数
在我们平常用的addEventListener方法中,一般只会用到两个参数,一个是需要绑定的事件,另一个是触发事件后要执行的函数,然而addEventListener还可以传入第三个参数:

element.addEventListener(event, function, useCapture);

第三个参数默认值是false,表示在事件冒泡阶段调用事件处理函数;如果参数为true,则表示在事件捕获阶段调用处理函数。如果不写第三个参数则默认在事件冒泡阶段调用事件处理函数。

1.冒泡

事件冒泡描述了浏览器如何处理针对嵌套元素的事件。

例如:这里有三个box依次嵌套 (big、center、small)

1691054483212.png

<style>
  .big {
    width: 300px;
    height: 300px;
    background-color: red;

  }
  .center {
    width: 200px;
    height: 200px;
    background-color: green;
  }
  .small {
    width: 100px;
    height: 100px;
    background-color: pink;
  }
</style>

<body>
  <div class="big">big
    <div class="center">center
      <div class="small">small</div>
    </div>
  </div>
</body>

接下来给最小的box添加点击事件:

  let small = document.querySelector('.small')
  
  small.addEventListener('click', (e) => {
    console.log('small');
  })

此时我们点击small会打印出"small"

接下来我们给center、big都加上点击事件

  big.addEventListener('click', (e) => {
    console.log('big');
  }, false)
  center.addEventListener('click', (e) => {
    console.log('center');
  }, false)
  small.addEventListener('click', (e) => {
    console.log('small');
  }, false)

此时我们再次点击small,发现依次打印出了small、center、big

1691054600258.png

也就是说三个box都触发了点击事件! 在这种情况下:

  • 最先触发small上的的点击事件
  • 然后是small的父元素center
  • 然后是center的父元素big

事件从被点击的最里面的元素冒泡而出

2.捕获

事件传播的另一种形式是事件捕获。这就像事件冒泡,但顺序是相反的:

//捕获
  big.addEventListener('click', (e) => {
    console.log('big');
  }, true)
  center.addEventListener('click', (e) => {
    console.log('center');
  }, true)
  small.addEventListener('click', (e) => {
    console.log('small');
  }, true)
  //冒泡
  big.addEventListener('click', (e) => {
    console.log('big');
  }, false)
  center.addEventListener('click', (e) => {
    console.log('center');
  }, false)
  small.addEventListener('click', (e) => {
    console.log('small');
  }, false)

此时我们点击small,发现输出:

image.png

可以看出,事件是先进行了捕获,然后进行了冒泡

3.事件委托

事件委托也称为事件代理。就是利用事件冒泡,把子元素的事件都绑定到父元素上。如果子元素阻止了事件冒泡,那么委托就无法实现

例如:我们如果循环给ul里的li元素添加点击事件的话,势必会增加内存损耗,影响性能

此时可以给li的父元素ul添加点击事件 这时就相当于给每个li都绑定了点击事件