JS:事件委托

Posted 郭佬

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JS:事件委托相关的知识,希望对你有一定的参考价值。

事件委托

  1. 事件流

    事件流描述的是从页面中接收事件的顺序。---JS高级程序设计(第3版)

    DOM Level 2 Events规定的事件流有三个阶段:①事件捕获阶段、②处于目标阶段、③事件冒泡阶段

    capture_and_bubbling

  2. 事件委托

    当需要添加的事件过多时,可以使用事件委托,而事件委托实际上利用了事件冒泡的特性。

    使用事件委托还需了解事件对象(event):在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含着所有与事件有关的信息。

    在此仅需知道在DOM标准中,event拥有一个target属性表示事件目标。

    event.target是一个触发事件的对象的引用。它与event.currentTarget不同, 当事件处理程序在事件的冒泡或捕获阶段被调用时。(mdn)

    具体Event详情可以查看MDN:Event


    如果你想要在大量子元素中单击任何一个都可以运行一段代码,您可以将事件监听器设置在其父节点上,并将事件监听器气泡的影响设置为每个子节点,而不是每个子节点单独设置事件监听器。(mdn)

    以下面的html代码为例:

    <ul id="list">
        <li id="one">do something</li>
        <li id="two">do something</li>
        <li id="three">do something</li>
    </ul>
    

    当需求是单击上面每个li标签都会执行各种操作时,使用事件委托是较好的选择。

    // bad (逐个 li 添加事件)
    let item1 = document.getElementById(\'one\');
    let item2 = document.getElementById(\'two\');
    let item3 = document.getElementById(\'three\');
    
    item1.addEventListener(\'click\', function(){...}, false);
    item1.addEventListener(\'click\', function(){...}, false);
    item1.addEventListener(\'click\', function(){...}, false);
    
    // event delegation (事件委托)
    let list = document.getElementById(\'list\');
    list.addEventListener(\'click\', function(e){
        if (e.target && e.target.nodeName == \'LI\') {
            switch (e.target.id) {
              case \'one\':
                do something;
                break;
    
              case \'two\':
                do something;
                break;
                    
              case \'three\':
                do something;
                break;
            }
          }
    }, false);
    

    注意:当li标签被如pdiv等撑满时,点击的targetp标签而不是li标签会导致无法正确执行click事件。

    以下面的html代码为例:

    <ul id="list">
        <li id="one">do something</li>
        <li id="two">do something</li>
        <!-- 这里的 li 里面有个 p 标签 -->
        <li id="three"><p>do something</p></li>
      </ul>
    

    这样的情况可以使用递归 or 循环来处理,毕竟事件委托是利用事件冒泡的特性。

    //递归
    let list = document.getElementById(\'list\');
    list.addEventListener(\'click\', function(e){
    	eventDelegation(e.target);
    }, false);
    
    function eventDelegation(target) {
    	if (target && target.nodeName == \'LI\') {
            switch (target.id) {
              case \'one\':
                do something;
                return;
    
              case \'two\':
                do something;
                return;
                    
              case \'three\':
                do something;
                return;
            }
        }
        return eventDelegation(target.parentNode);
    }
    
  3. 使用事件委托的优点

    a.减少DOM操作,使事件处理时间减少。
    b.减少内存空间的使用,提升性能。

    因为在javascript中,每个函数都是对象,对象越多,占用的内存也就越多,合理使用事件委托可以减少内存的占用。

  4. 注意事项

    比较适合使用事件委托的事件:clickmousedownmouseup等,而如mouseoutmouseover等则不太适合使用事件委托(虽然mouseout这些事件也冒泡,但通常需要确定元素的位置,所以不太推荐使用事件委托)。

    另外不会冒泡的事件是不适合使用事件委托的。

以上是关于JS:事件委托的主要内容,如果未能解决你的问题,请参考以下文章

JS中的事件(对象,冒泡,委托,绑定)

js事件委托

(JS 事件委托)如何删除目标元素?

js事件委托

js事件代理(事件委托)最简单的理解

JS 中的事件绑定事件监听事件委托