js之事件委托

130 阅读2分钟

js之事件委托

基本概念

  • 事件代理(Event Delegation),又称之为事件委托。

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

    • 利用事件的冒泡传播机制,只给最外层容器的相关事件行为绑定方法,这样不管触发容器内部哪一个后代元素的相关事件行为,都会出传播到容器上,出发他的对应事件行为。
  • 核心

    • 基于事件的冒泡传播机制完成

事件委托的优点

  • 可以大量节省内存占用,减少事件注册,比如在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身上,执行事件的时候再去匹配判断目标元素。

  • 可以实现当新增子对象时无需再次对其绑定(动态绑定事件)
    • 在很多时候,我们需要通过 AJAX 或者用户操作动态的增加或者删除列表项li元素,那么在每一次改变的时候都需要重新给新增的元素绑定事件,给即将删去的元素解绑事件;
    • 如果用了事件委托就没有这种麻烦了,因为事件是绑定在父层的,和目标元素的增减是没有关系的,执行到目标元素是在真正响应执行事件函数的过程中去匹配的;所以使用事件在动态绑定事件的情况下是可以减少很多重复工作的。

基本实现

  • JavaScript原生实现事件委托
<ul id="myLinks">
  <li id="goSomewhere">Go somewhere</li>
  <li id="doSomething">Do something</li>
  <li id="sayHi">Say hi</li>
</ul>

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

    var item1 = document.getElementById("goSomewhere");
    var item2 = document.getElementById("doSomething");
    var item3 = document.getElementById("sayHi");
 
    item1.onclick = function() {
      location.href = "http://www.baidu.com";
    };
    item2.onclick = function() {
      document.title = "事件委托";
    };
    item3.onclick = function() {
      alert("hi");
    };
  • 如果在一个复杂的 Web 应用程序中,对所有可单击的元素都采用这种方式,那么结果就会有数不 清的代码用于添加事件处理程序。此时,可以利用事件委托技术解决这个问题。使用事件委托,只需在 DOM 树中尽量最高的层次上添加一个事件处理程序,如下面的例子所示
    var item1 = document.getElementById("goSomewhere");
    var item2 = document.getElementById("doSomething");
    var item3 = document.getElementById("sayHi");
 
    document.addEventListener("click", function (event) {
      var target = event.target;
      switch (target.id) {
        case "doSomething":
          document.title = "事件委托";
          break;
        case "goSomewhere":
          location.href = "http://www.baidu.com";
          break;
        case "sayHi": alert("hi");
          break;
      }
    })