事件委托

136 阅读2分钟

前置知识: Dom事件模型

首先,让我们来看看这段html代码

    <ul>
        <li>点我,我的文字会变蓝</li>
        <li>点我,我的文字会变蓝</li>
        <li>点我,我的文字会变蓝</li>
        <li>点我,我的文字会变蓝</li>
        <li>点我,我的文字会变蓝</li>
        <li>点我,我的文字会变蓝</li>
        <li>点我,我的文字会变蓝</li>
        <li>点我,我的文字会变蓝</li>
        <li>点我,我的文字会变蓝</li>
        <li>点我,我的文字会变蓝</li>
    </ul>

需求是:当点击li的时候里面的文字变蓝
当然,我们可以一个一个绑定事件

li1.addEventListener('click',()=>{
    li1.style.color = 'blue'
});
li2.addEventListener('click',()=>{
    li2.style.color = 'blue'
});
......
......

但这样有几个缺点:

1. 占用内存
2. 代码量繁多,如果有100个li甚至更多的话岂不是要花费大量的无用时间

那我们换个角度,如果监听li复杂的话,我们是不是可以来监听它们的祖先元素,根据事件冒泡,并且运用条件语句和e.target来判断点击的是否是li标签,如果是的话,则执行对应的事件。

ul.addEventListener('click',(e)=>{
    if(e.target.tagName.toLowerCase() === 'li'){
        e.target.style.color = 'blue'
    }
})

这样的话,监听的元素从原来所有的li变成一个ul,这样既减少了占用的内存,提高了性能,也减轻了代码量。


让我们来看第二段html代码

    <ul>
        <li>点我,我的文字会变蓝</li>
        <button>点我,会增加li</button>
    </ul>

需求是:每次点击按钮增加的li上都要绑定相同的监听事件
这次需要监听的是动态元素,我们也可以用相同的方法去委托ul去监听动态元素

ul.addEventListener('click',(e)=>{
    if(e.target.tagName.toLowerCase() === 'li'){
        e.target.style.color = 'blue'
    }
})

这种把原本需要绑定在子元素的响应事件委托给父元素,让父元素担当事件监听的职务的技术手段就叫做

事件委托


由上面的事例可以看出事件委托的优点

1.可以监听动态的元素
2.减少监听数量
3.提高性能

注意

    <ul id="ul">
        <li id="li1"> <span>点我,我的文字会变蓝</span></li>
        <li>点我,我的文字会变蓝</li>
        <li>点我,我的文字会变蓝</li>
        <li>点我,我的文字会变蓝</li>
        <li>点我,我的文字会变蓝</li>
        <li>点我,我的文字会变蓝</li>
        <li>点我,我的文字会变蓝</li>
        <li>点我,我的文字会变蓝</li>
        <li>点我,我的文字会变蓝</li>
        <li>点我,我的文字会变蓝</li>
    </ul>

当li中有其他的元素例如span时,我们点击的元素就会变为span,而不是li,就不会执行事件。所以我们需要嵌套地找出点击的元素的祖先元素是否是li

ul.addEventListener("click", (e) => {
  let x = e.target;
  while (x.tagName.toLowerCase() !== "li") {
    if (x === ul) {
      x = null;//作为是否找到对应元素的判断,没找到,则是null;
      break;//到监听的父节点,还是没有找到li,退出循环,防止死循环;
    }
    x = x.parentNode;
  };
  if (x) {
    x.style.color = "blue";
  }
});