欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JS:事件委托

程序员文章站 2022-07-11 23:52:59
事件委托 1. 事件流 事件流描述的是从页面中接收事件的顺序。 JS高级程序设计(第3版) 规定的事件流有三个阶段:①事件 捕获 阶段、②处于 目标 阶段、③事件 冒泡 阶段 2. 事件委托 当需要添加的事件过多时,可以使用 事件委托 ,而事件委托实际上利用了事件 冒泡 的特性。 使用事件委托还需了 ......

事件委托

  1. 事件流

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

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

    JS:事件委托

  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这些事件也冒泡,但通常需要确定元素的位置,所以不太推荐使用事件委托)。

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