JavaScript事件流和事件委托

梳理关于事件的知识点 

基本概念

事件冒泡: 

  <div id='box1'>
    box1
    <div id='box2'>
      box2
      <div id='box3'>
        box3
      </div>
    </div>
  </div>

  let box1 = document.getElementById('box1')
  let box2 = document.getElementById('box2')
  let box3 = document.getElementById('box3')

  // DOM0级事件处理程序

  box1.onclick = () => {
    console.log('box1');
  }

  box2.onclick = () => {
    console.log('box2'); // box2 -> box1
  }
  
  box3.onclick = () => {
    console.log('box3'); // box3 -> box2 -> box1
  }

  

当我们点击box1时都知道输出box1,可是当我们点击box3时弹出什么呢?

出现该结果的原因是事件冒泡导致的,为了只打印box3,需要阻止事件冒泡

  box3.onclick = () => {
    event.stopPropagation();
    console.log('box3'); // box3
  }

事件代理(Event Delegation),又称之为事件委托。是JavaScript中常用绑定事件的常用技巧。

顾名思义,“事件代理”即是把原本需要绑定在子元素的响应事件(click、keydown......)委托给父元素,让父元素担当事件监听的职务。

事件代理的原理是DOM元素的事件冒泡。

就是把你的事件委托给别人(父级),利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。

举个通俗的例子

比如一个宿舍的同学同时快递到了,一种方法就是他们一个个去领取,还有一种方法就是把这件事情委托给宿舍长,让一个人出去拿好所有快递,然后再根据收件人一 一分发给每个宿舍同学;

在这里,取快递就是一个事件,每个同学指的是需要响应事件的 DOM 元素,而出去统一领取快递的宿舍长就是代理的元素,所以真正绑定事件的是这个元素,按照收件人分发快递的过程就是在事件执行中,需要判断当前响应的事件应该匹配到被代理元素中的哪一个或者哪几个。

如上图所示,事件传播分成三个阶段:

  • 捕获阶段:从window对象传导到目标节点(上层传到底层)称为“捕获阶段”(capture phase),捕获阶段不会响应任何事件;
  • 目标阶段:在目标节点上触发,称为“目标阶段”
  • 冒泡阶段:从目标节点传导回window对象(从底层传回上层),称为“冒泡阶段”(bubbling phase)。
  • 事件代理即是利用事件冒泡的机制把里层所需要响应的事件绑定到外层;

 

 

事件委托的优点 

【1】可以大量节省内存占用,减少事件注册,比如在ul上代理所有li的click事件就非常棒

<ul id="list">
  <li>item 1</li>
  <li>item 2</li>
  <li>item 3</li>
  ......
  <li>item n</li>
</ul>
// ...... 代表中间还有未知数个 li

如上面代码所示,如果给每个li列表项都绑定一个函数,那对内存的消耗是非常大的。

因此较好的解决办法就是将li元素的点击事件绑定到它的父元素ul身上,执行事件的时候再去匹配判断目标元素。 

【2】可以实现当新增子对象时无需再次对其绑定(动态绑定事件)

假设上述的例子中列表项li就几个,我们给每个列表项都绑定了事件;

在很多时候,我们需要通过 AJAX 或者用户操作动态的增加或者删除列表项li元素,那么在每一次改变的时候都需要重新给新增的元素绑定事件,给即将删去的元素解绑事件;

如果用了事件委托就没有这种麻烦了,因为事件是绑定在父层的,和目标元素的增减是没有关系的,执行到目标元素是在真正响应执行事件函数的过程中去匹配的;所以使用事件在动态绑定事件的情况下是可以减少很多重复工作的。

基本实现

【1】JavaScript原生实现事件委托

比如我们有这样的一个 HTML 片段:


<ul id="myLinks">
  <li id="goSomewhere">Go somewhere</li>
  <li id="doSomething">Do something</li>
  <li id="sayHi">Say hi</li>
</ul>

按照传统的做法,需要像下面这样为它们添加 3 个事 件处理程序

  let item1 = document.getElementById('goSomeWhere');
  let item2 = document.getElementById('doSomething');
  let item3 = document.getElementById('sayHi');

  item1.addEventListener('click', () => {
    location.href = 'http://baidu.com.cn'
  }, false)

  item2.addEventListener('click', () => {
    document.title = 'I changed the document title'
  }, false)

  item3.addEventListener('click', () => {
    console.log('say hi');
  }, false)

如果在一个复杂的 Web 应用程序中,对所有可单击的元素都采用这种方式,那么结果就会有数不 清的代码用于添加事件处理程序。

此时,可以利用事件委托技术解决这个问题。使用事件委托,只需在 DOM 树中尽量最高的层次上添加一个事件处理程序,

如下面的例子所示

 //  使用事件委托之后,提高性能
  let list = document.getElementById('myLinks')
  list.addEventListener('click', (event) => {
    let target = event.target;
    switch (target.id) {
      case 'goSomeWhere':
        location.href = 'http://baidu.com.cn'
        break;
      case 'doSomething':
        document.title = 'I changed the document title'
        break;
      case 'sayHi':
        console.log('say hi');
        break;
      default:
        break;
    }
  })

 

此文参考链接地址: https://blog.csdn.net/qq_38128179/article/details/86293394

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值