由于事件会在冒泡阶段向上传播到父节点,因些可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件。这种方法叫做事件代理(delegation),也可以叫做事件委托。简单来说,它是基于事件冒泡,只制定一个时间来处理程序,就可以管理某一类型的所有行为绑定事件。可以看出它们要用到事件目标的target和srcElement属性。

  举一个简单的例子来说,页面上有如下代码,想要给最里面的a加一个click点击事件,那么这个事件就会一层一层的往外执行,执行顺序a->li->ul。现在我们给最外面的ul加上点击事件,那么里面的li,a执行点击事件的时候,都会冒泡到最外层的div上都会触发,这就是事件委托。

    <ul>
        <li>
            <a href="javascript:;"></a>
        </li>
    </ul>

  如下面的代码中,我们想实现点击一下按钮可以新增2个li,且每个li在点击的时候都能弹出我是第几个li这一需求给动态的元素绑定事件。

    <link rel="stylesheet" href="./css/reset.min.css" />
    <style>
      .box {margin: 20px auto;width: 200px;}
      .newList {box-sizing: border-box;border: 2px solid #bbbbbb;padding: 5px;}
      .newList li { line-height: 35px;border-bottom: 1px dotted #cccccc;}
      .createBtn {box-sizing: border-box;margin-top: 10px;width: 80px;height: 30px; border: 1px solid #cccccc;}
      
    </style>
    <div class="box">
      <ul class="newList">
        <li>我是第1个li</li>
        <li>我是第2个li</li>
      </ul>
      <button class="createBtn">新增按钮</button>
    </div>

  我们用到jQuery可以更加方便的操作DOM,在没有用事件委托之前,我们用循环绑定。可以先写一个headle方法,在这个方法中,我们先获取所有的li,然后遍历每一个lis让其弹出“我是第几个li”。然后给按钮绑定事件,点击增加2个li。刚开始我们执行一次headle方法,然后给按键绑定事件增加li后再执行一次headle方法。这样一看我们操作DOM的次数过于频繁,引起浏览器重绘与重排的次数。这样很消耗性能。

    <script src="../../node_modules/jquery/dist/jquery.min.js"></script>
    <script>
      let $newList = $(".newList"),
        $lis = null,
        $createBtn = $(".createBtn");
      function handle() {
        $lis = $newList.children("li");
        $lis.each(function (index, item) {
          $(item).click(function () {
            alert(`我是第${index + 1}个li`);
          });
        });
      }
      handle();
      let count = 2;
      $createBtn.click(function () {
        let str = ``;
        for (let i = 0; i < 2; i++) {
          count++;
          str += `<li>我是第${count}个li</li>`;
        }
        $newList.append(str);
        handle();
      });

    这里用父级newList做事件处理。当li点击时,由于冒泡机制,事件会冒泡到newList上,newList上的事件就会被触发。当然我们点击newList时这个事件也会触发,这时就需要用到Event对象提供的target属性,它可以返回事件的目标节点,我们称之为事件源,这时我们只是获取了当前节点的位置并不知道节点的名称,这时要用到tagName来获取具体是什么标签名(这里标签名是大写)具体代码如下,这样的话每次只执行一次DOM操作,大大减少了DOM的操作,进行了性能上的优化。但使用“事件委托”时,并不是把事件委托给的元素越靠近顶层就越好。如果DOM嵌套结构很深,事件冒泡通过大量祖先元素也会导致性能损失。

let $newList = $(".newList"),
        $createBtn = $(".createBtn"),
        count =2;

      $newList.click(function (ev) {
        let target = ev.target,
          $target = $(target);
        target.tagName === "LI"
          ? alert(`我是第${$target.index()+1}个li`)
          : null;
      });

      $createBtn.click(function () {
        let str = ``;
        for (let i = 0; i < 2; i++) {
          count++;
          str += `<li>我是第${count}个li</li>`;
        }
        $newList.append(str);
      }); 

  

posted on 2020-06-04 22:36  人称小小贩  阅读(177)  评论(0编辑  收藏  举报