《事件委托》

134 阅读3分钟

概述

事件委托也叫事件代理,就是把目标节点的事件绑定到祖先节点上。基于事件传播过程,逐层冒泡总能被祖先节点捕获。可以只指定一个事件处理程序,就可以管理某一类型的所有事件。这样的好处是省监听数,可以监听动态元素。

举个例子,公司里有个三个同事预计在同一天收到快递。为签收快递,有两种方法:一、三个人在公司门口等快递;二、委托给前台代为签收。

现实生活中我们一般采用委托的方案。前台收到快递后,她会判断收件人是谁,然后按照收件人的要求签收,甚至代为付款。这种方案还有一个优势,那就是即使公司里来了新员工(不管多少),前台也会在收到寄给新员工的快递后核实并代为签收。

这里其实有两层意思: 第一,现在委托前台的同事是可以代为签收的,即程序中的现有的dom节点是有事件的;

第二,新员工也是可以被前台代为签收的,即程序中新添加的dom节点也是有事件的。

使用场景

  • 场景一 很多的dom需要添加事件处理,比如100个按钮添加点击事件,每个按钮都有相同的点击事件,然而这样就需要遍历所有的按钮,来给他们给他们添加事件。

这样就会延长整个页面交互就绪时间,我们只需要监听这100个按钮的祖先,等冒泡的时候判断target是不是这个100个按钮中的一个。

//div为100个button的祖先元素
div.addEventLister('click',(e)=>{
 const t = e.target
 if(t.tagName.toLowerCase()==='button'){
   console.log('button data-id 是'+ t.dataset.id);
   console.log('button 内容是'+ t.textContent);
 }
})
  • 场景二 要监听不存在的元素点击事件,即还没有元素还没有被添加进去。
//div里延时创建一个button
setTimeout(() => {
  const button = document.createElement('button')
  button.textContent = 'click'
  div.appendChild(button)
}, 1000);

div.addEventListener('click',(e)=>{
  const t = e.target
  if(t.tagName.toLowerCase()==='button'){
    console.log('button :'+t.textContent);
  }
})

原理

事件委托利用了冒泡原理来实现,即事件从最深的节点开始,然后逐步向上传播事件。

封装事件委托

有一个自己定义的on函数,当用户点击#div里的button时调用。

on('click','#div','button',()=>{
  console.log('button被点击');
})
function on(eventType,element,selector,fn){
  if(!(element instanceof Element)){
    element = document.querySelector(element)
  }//判断是不是个元素,不是则去找这个元素
  element.addEventListener(eventType,(e)=>{
    const t = e.target
    if(t.matches(selector)){
      fn(e)
    }
  })
}

JS不支持事件,JS只是调用DOM提供的addEventListener。

其他内容

target和currentTarget的区别:

  • e.target——用户操作的元素
  • e.currentTarget——程序员监听的元素 注意e对象传给所有监听函数,等事件结束后就不存在了。