JavaScript事件委托

首先来例子:给列表里面的三个元素绑定事件,点击它们的时候弹出各自元素里的数字。

了解了如何给页面上的元素绑定事件之后,只需要遍历节点,依次绑定就可以了:

<html>
  <body>
    <ul id="container">
      <li>1</li>
      <li>2</li>
      <li>3</li>
    </ul>
    <script>
      function clickHandler(e) {
        alert(e.target.innerHTML)
      }
      var nodeList = document.querySelectorAll('li')
      nodeList.forEach(function(item) {
        item.addEventListener('click', clickHandler)
      })
    </script>
  </body>
</html>
复制代码

现在如果将列表元素的数量扩展到更多,或者是动态的无限个。例如:当我们刷微博的时候,给微博点赞,下拉会持续的加载更多条微博。这个时候如果还用上面的方式来绑定的话,既影响性能,也不优雅。于是就有了事件委托:

<html>
  <body>
    <ul id="container">
      <li>1</li>
      <li>2</li>
      <li>3</li>
    </ul>
    <script>
      function clickHandler(e) {
        alert(e.target.innerHTML)
      }
      var container = document.querySelector('#container')
      container.addEventListener('click', clickHandler)
    </script>
  </body>
</html>
复制代码

将事件绑定到列表的外层容器上,当我们点击容器里的所有元素(包括容器本身),都会触发点击事件,我们只需要绑定一次,就可以处理里面所有元素的对应事件,这就叫事件委托。

测试一下上面这个例子,会发现,点击容器的时候,也会响应事件,与我们预期不符,只需要在事件处理时做一点过滤就可以了:

<html>
  <body>
    <ul id="container">
      <li>1</li>
      <li>2</li>
      <li>3</li>
    </ul>
    <script>
      function clickHandler(e) {
        if (e.target.tagName.toLocaleLowerCase() === 'li') {
          alert(e.target.innerHTML)
        }
      }
      var container = document.querySelector('#container')
      container.addEventListener('click', clickHandler)
    </script>
  </body>
</html>
复制代码

只有在点击到li节点的时候才响应。由于上面的例子过于简单,没有办法完全暴露出实际场景中遇到的问题,不过解决起来的思路是一样的。

试试JQuery提供事件委托的方法:

<html>
  <body>
    <ul id="container">
      <li>1</li>
      <li>2</li>
      <li>3</li>
    </ul>
    <script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.4.1.min.js"></script>
    <script>
      function clickHandler(e) {
        alert(e.target.innerHTML)
      }
      $('#container').on('click', 'li', clickHandler)
    </script>
  </body>
</html>
复制代码

至此,已经可以愉快的使用事件委托来处理类似的事件绑定场景了。但是还没有结束,事件委托是基于DOM事件冒泡的机制来实现的。我们还需要了解一下事件冒泡,因为这个是考点...

我在网上盗了一张图来说明事件捕获和事件冒泡。(怎么又多了一个事件捕获?这么理解就可以了:事件捕获是在绑定事件的时候可选的另一种事件触发机制。)

这里我们只管事件冒泡,图说很直白了,就是点击事件触发后,会从最底层的元素,依次向上触发父元素的点击事件~

冒泡过程当然也是可以阻止的,如果有需要的话。

最后,增加一点难度,给要代理的节点添加一些子节点,这样就没办法直接通过事件触发的节点来,实现了一个简单版本的事件委托函数:

<html>
  <body>
    <ul id="container">
      <li data="1"><div>1</div><div>3</div></li>
      <li data="2"><div>2</div><div>2</div></li>
      <li data="3"><div>3</div><div>1</div></li>
    </ul>
    <script>
      function clickHandler(e) {
        // DOM结构变得复杂,通过li节点上的data属性来标识
        alert(e.realTarget.getAttribute('data'))
      }

      // 获取到事件触发的最底层节点后,需要向上找需要委托的节点,这里通过tagName来标识
      function findTarget(el, tagName, container) {
        // 最外层直到事件委托的容器,如果没有找到需要委托的节点就放弃
        if (el == container) {
          return null
        }
        if (el.tagName.toLocaleLowerCase() === tagName) {
          return el
        }
        return findTarget(el.parentNode, tagName, container)
      }

      function eventDelegate(container, type, tagName, handler) {
        container.addEventListener(type, function(e){
          var target = findTarget(e.target, tagName, container)
          if (target != null) {
            e.realTarget = target
            handler(e)
          }
        })
      }
      eventDelegate(document.querySelector('#container'), 'click', 'li', clickHandler)
    </script>
  </body>
</html>
复制代码

小结

事件委托应该属于事件绑定时的一个优化方案。当我们写简单demo的时候,通常不需要考虑,但是实际场景中会经常用到~

转载于:https://juejin.im/post/5d08b665e51d45105d63a512

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值