DOM事件委托

89 阅读2分钟

事件委托原理:事件捕获与事件冒泡。通俗来说就是找一个代理人做本来自己该做的事。

下面引入两个场景:

场景一:你要给100个按钮添加点击事件,咋办?

答:监听这100个按钮的祖先,等冒泡的时候判断target是不是这100个按钮中的一个。

场景二:你要监听目前不存在元素的点击事件,咋办?

答:监听这个元素的祖先,等点击的时候再看看是不是我想要监听的元素。


场景一代码

//html部分
<div id='div1'>
<button>click 1</button>
<button>click 2</button>
……
<button>click 100</button>
</div>
//js部分
div1.addEventListener('click',(e)=>{
const t=e.target  //用一个变量获取当前被点击的元素
if(t.tagName.toLowerCase()==='button')  //t的标签名转小写后为button
console.log('button的内容是'+t.textContent)
})

如果要给多个元素绑定事件,可能需要用到循环,且若为同一事件则十分浪费内存空间。对此,事件委托的第一个优点就是:省内存

场景二代码

//html部分
<div id='div1'><div>
//js部分
setTimeout(()=>{
const btn=document.createElement('button')
btn.textContent='click1'
div1.appendChild(btn)
},1000) //设置一个1s后的定时器,往div中添加按钮
div1.addEventListener('click',(e)=>{
const t=e.target
if(t.tagName.toLowerCase()==='button'){
console.log('button被点击了')
}
})

如果要给还未出现的元素绑定事件,必须用到事件委托,因为这时运用常规的DOM方法或者JQuery方法是获取不到元素的,因为定时器的队列是放在“稍后”执行的。对此,事件委托的第二个优点就是:可以监听动态元素

小总结:事件委托两大优点:省内存;可动态


封装一个事件委托函数

上述的场景中对于特定的场景写特定的代码,这个就叫做写业务。(这个就是日常的程序猿做的事情)但如果你能把业务代码抽象出来,写一套代码解决该类场景所有类似问题,那你就牛逼了,这个行为叫做造轮子

//用户点击#div1里的button时,调用fn函数
//具体业务场景
on('click','#div1','button',()=>{
console.log('button被点击了')
})
//轮子,封装一个on函数
function on(eventType, element, selector, fn) { //传进4个参数,为事件类型,元素,选择器,自定义函数
  if (!(element instanceof Element)) {  //若element不是一个元素
    element = document.querySelector(element)  //获取元素
  }
  element.addEventListener(eventType, (e) => {
    const t = e.target
    if (t.matches(selector)) { //判断一个元素是否满足一个选择器,返回值为bool
      fn(e)  //调用函数
    }else{
      console.log('别点了,这个元素没有监听器')
    }
  })
}

一个疑问:JS支持事件吗?

答:不支持,DOM事件不属于JS的功能,属于浏览器提供的DOM功能(含冒泡,捕获等),JS只是调用了DOM提供的addEventListener这个API接口而已。

再次回到事件委托

本来是孩子自己要做的事情(添加侦听器),却交给了爸爸来做(在爸爸身上添加侦听器),这个就叫做事件委托。