DOM 事件委托

95 阅读1分钟

前端实现事件委托,依赖于 DOM 事件模型的冒泡机制。由于事件的捕获冒泡机制,我们可以在父元素上添加一类事件监听器,达到监听父元素及其所有子元素所有关于此事件的目的。

优点

  1. 省监听数节约内存
  2. 可以监听动态元素

普通实现

一般如果需要作为委托对象的父元素内部子元素很单纯,如 ul 仅嵌套 li 元素的场景。以鼠标点击事件为例,我们一般可以这样写:

ul.addEventListener('click', function(e){
  if(e.target.tagName.toLowerCase() === 'li') {
    fn() // 执行某个函数
  }
})

但是,如果 li 里面还有 span 元素,那么此时用户如果点击的是 li 里面的 span 元素,就没法触发 fn,这显然达不到监听所有子元素的效果。

完备实现

了解了上面一种实现的缺陷,我们就可以知道改进的思路了。显然我们需要判断用户操作对象的祖先元素里是否有 ul 元素里面的 li 元素,如果有就应该执行对应的委托函数,所以我们可以写出下面的代码:

<ul>
  <li><span>1</span></li>
  <li><span>2</span></li>
  <li><span>3</span></li>
</ul>
function delegate(element, eventType, selector, fn) {
  element.addEventListener(eventType, e => {
    let el = e.target;
    while (!el.matches(selector)) {
      if (element === el) {
        el = null;
        break
      }
      el = el.parentNode;
    }
    el && fn.call(el, e, el);
  })
  return element;
}

delegate(document,'click','li',(e)=>console.log(e))