事件委托


事件委托是不在目标dom上绑定触发事件,而委托给在目标dom上层。这样做可以减少事件的注册,节省内存(比如在ul代理li的click事件),优化dom节点,当在ul中增加新的li时,不需要再去绑定click事件。
事件委托,首先要了解事件传播的过程 捕获 和 冒泡

事件传播

事件传播分为三个阶段

  1. 捕获阶段:事件从上层节点传到目标节点,称为捕获阶段(capture phase)
  2. 目标阶段:在目标节点上触发,称为目标阶段(target phase)。
  3. 冒泡阶段:从目标节点传回到上层节点,曾为冒泡阶段(bubbing phase)
    html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <style>
      .child {
        background-color: silver;
        margin: 10px;
      }
    </style>
    <title>Document</title>
  </head>
  <body>
    <div
      id="grandfather"
      class="grandfather"
      style="height:200px;width:400px;background-color: indianred"
    >
      grandfather
      <ul
        id="father"
        class="father"
        style="margin:40px;background-color: cornflowerblue"
      >
        <li id="child1" class="child">child1</li>
        <li id="child2" class="child">child2</li>
        <li id="child3" class="child">child3</li>
        <li id="child4" class="child">child4</li>
      </ul>
    </div>
    <script src="./index.js"></script>
  </body>
</html>

js

const grandfather = document.querySelector('#grandfather'),
  father = document.querySelector('#father'),
  childern = document.querySelectorAll('.child');

grandfather.addEventListener('click', function(e) {
  console.log(`grandfather id: ${this.id} targetId: ${e.target.id}`);
});

father.addEventListener('click', function(e) {
  console.log(`father id: ${this.id} targetId: ${e.target.id}`);
});

if (childern && childern.length) {
  for (const child of childern) {
    child.addEventListener('click', function(e) {
      console.log(`child id: ${this.id} targetId: ${e.target.id}`);
    });
  }
}

在这里插入图片描述

  • 当点击红色的grandfather区域时
    输出结果
    grandfather id: grandfather targetId: grandfather
  • 当点击蓝色father区域时
    输出结果
    father id: father targetId: father
    grandfather id: grandfather targetId: father
  • 当点击银色child区域时
    输出结果
    child id: child2 targetId: child2
    father id: father targetId: child2
    grandfather id: grandfather targetId: child2

addEventListener还可以传入第三个参数,默认是false(在冒泡阶段触发),true(在捕获阶段触发)
可以看到当我们点击child2时,father和grandfather的click事件也会触发,this指向的是绑定的dom,但是e.target始终指向的目标节点,所以根据这个结果,可以把child的click事件委托给father或者grandfather

事件委托

我们可以将li(child)的click事件委托给ul(father),这样就不需要在每个li上都绑定一个click事件了,把child的click事件注释掉就可以了

const grandfather = document.querySelector('#grandfather'),
  father = document.querySelector('#father'),
  childern = document.querySelectorAll('.child');

grandfather.addEventListener(
  'click',
  function(e) {
    console.log(`grandfather id: ${this.id} targetId: ${e.target.id}`);
  }
);

father.addEventListener('click', function(e) {
  console.log(`father id: ${this.id} targetId: ${e.target.id}`);
});

// if (childern && childern.length) {
//   for (const child of childern) {
//     child.addEventListener('click', function(e) {
//       console.log(`child id: ${this.id} targetId: ${e.target.id}`);
//     });
//   }
// }

当再点击child2时
输出的结果
father id: father targetId: child2
grandfather id: grandfather targetId: child2

阻止事件的继续传播

事件委托给我带来很多方便,但是当事件向上冒泡时可能触发我们不想要的触发结果,所以我们还可以阻止事件的传播,应用方法
e.stopPropagation();

const grandfather = document.querySelector('#grandfather'),
  father = document.querySelector('#father'),
  childern = document.querySelectorAll('.child');

grandfather.addEventListener('click', function(e) {
  console.log(`grandfather id: ${this.id} targetId: ${e.target.id}`);
});

father.addEventListener('click', function(e) {
  console.log(`father id: ${this.id} targetId: ${e.target.id}`);
  // 阻止事件传播
  e.stopPropagation();
});

// if (childern && childern.length) {
//   for (const child of childern) {
//     child.addEventListener('click', function(e) {
//       console.log(`child id: ${this.id} targetId: ${e.target.id}`);
//     });
//   }
// }

当再点击child2时
输出的结果
father id: father targetId: child2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值