美文网首页
事件委托

事件委托

作者: 你喜欢吃青椒吗_c744 | 来源:发表于2019-08-06 15:25 被阅读0次

    基本概念

    事件委托,通俗地来讲,就是把一个元素响应事件(click、keydown......)的函数委托到另一个元素;

    一般来讲,会把一个或者一组元素的事件委托到它的父层或者更外层元素上,真正绑定事件的是外层元素,当事件响应到需要绑定的元素上时,会通过事件冒泡机制从而触发它的外层元素的绑定事件上,然后在外层元素上去执行函数。

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

    事件冒泡与捕获

    image.png

    为什么用事件委托

    1:绑定事件越多,浏览器内存占用越大,严重影响性能。

    2:ajax的出现,局部刷新的盛行,导致每次加载完,都要重新绑定事件

    3:部分浏览器移除元素时,绑定的事件并没有被及时移除,导致的内存泄漏,严重影响性能

    4:大部分ajax局部刷新的,只是显示的数据,而操作却是大部分相同的,重复绑定,会导致代码的耦合性过大,严重影响后期的维护。

    事件委托影响性能的因素:

    • 元素中,绑定事件委托的次数
    • 点击的最底层元素,到绑定事件元素之间的DOM层数

    什么时候选择使用事件委托

    1:只在必须的地方,使用事件委托,比如:ajax的局部刷新区域

    2:尽量的减少绑定的层级,不在body元素上,进行绑定

    3:减少绑定的次数,如果可以,那么把多个事件的绑定,合并到一次事件委托中去,由这个事件委托的回调,来进行分发。

    一个例子

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
    <ul id="ul-test">
        <li>0</li>
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
        <li>6</li>
        <li>7</li>
        <li>8</li>
        <li>9</li>
    </ul>
    </body>
    <script type="text/javascript">
      var oUl=document.getElementById("ul-test");
      var oLi=oUl.getElementsByTagName("li");
      for(var i=0,len=oLi.length;i<len;i++){
        oLi[i].addEventListener("click",function(){
          alert(this.innerHTML)
        })
      }
    </script>
    </html>
    

    问题在于:

    • for循环,循环的是li,10个li就循环10次,绑定10次事件,1000个就循环了1000次,绑定1000次事件!
    • 如果li不是本来就在页面上的,是未来元素,是页面加载了,再通过js动态加载进来了,上面的写法是无效的,点击li是没有反应的!应该怎么解决以上问题?

    解决的办法就是通过事件委托

    var oUl=document.getElementById("ul-test");
    oUl.addEventListener("click",function(ev){
      console.log(ev)
      var ev=ev||window.event;// 兼容性处理
      var target=ev.target||ev.srcElement;
       // 获取到目标阶段指向的元素。如果点击的最底层是li元素
      if(target.tagName.toLowerCase()==='li'){
        alert(target.innerHTML)
      }
    })
    

    原理

    事件的传播有三个阶段:
    当一个事件发生以后,它会在不同的DOM节点之间传播(propagation)。这种传播分成三个阶段:

    • 第一阶段:从window对象传导到目标节点,称为“捕获阶段”(capture phase)。
    • 第二阶段:在目标节点上触发,称为“目标阶段”(target phase)。
    • 第三阶段:从目标节点传导回window对象,称为“冒泡阶段”(bubbling phase)。

    这种三阶段的传播模型,会使得一个事件在多个节点上触发。比如,假设点击<div>之中嵌套一个<p>节点。

    <div>
      <p>Click Me</p>
    </div>
    

    如果对这两个节点的click事件都设定监听函数,则click事件会被触发四次。

    • 捕获阶段:事件从<div>向<p>传播时,触发<div>的click事件;
    • 目标阶段:事件从<div>到达<p>时,触发<p>的click事件;
    • 目标阶段:事件离开<p>时,触发<p>的click事件;
    • 冒泡阶段:事件从<p>传回<div>时,再次触发<div>的click事件。

    注意,用户点击网页的时候,浏览器总是假定click事件的目标节点,就是点击位置的嵌套最深的那个节点(嵌套在<div>节点的<p>节点)。所以,<p>节点的捕获阶段和冒泡阶段,都会显示为target阶段。

    事件传播的最上层对象是window,接着依次是documenthtml(document.documentElement)body(document.body)。也就是说,如果<body>元素中有一个<div>元素,点击该元素。事件的传播顺序,在捕获阶段依次为window、document、html、body、div,在冒泡阶段依次为div、body、html、document、window。

    定义

    由于事件会在冒泡阶段传向父节点,因此可以把子节点的监听函数绑定在父节点上,用父节点的监听函数统一处理多个子节点的事件,这就是事件代理。

    var ul = document.querySelector('ul');
    
    ul.addEventListener('click', function(event) {
      if (event.target.tagName.toLowerCase() === 'li') {
        // some code
      }
    });
    

    上面这个函数事件监听绑在ul身上,但是监听到点击li的事件,然后处理li点击后的回调。

    就算li是动态添加进来的依然能够监听到。

    总结

    由于一个事件在传播的过程中有三个阶段,由最外层的父节点一层层传递到最里面的子节点,先是捕获阶段,到目标阶段,再到冒泡阶段。如果我们想监听到动态添加的子节点的事件,我们可以把事件绑在父节点上,利用event.target,筛选到子节点,处理事件相应的回调!!!

    参考文章

    JavaScript 事件委托详解

    深入理解-事件委托

    事件委托(事件代理)

    相关文章

      网友评论

          本文标题:事件委托

          本文链接:https://www.haomeiwen.com/subject/yvsidctx.html