事件委托

127 阅读2分钟

事件委托

事件委托,就是把一个元素响应事件(click、keydown......)的函数委托到另一个元素;

一般来讲,会把一个或者一组元素的事件委托到它的父层或者更外层元素上,真正绑定事件的是外层元素,当事件响应到需要绑定的元素上时,会通过事件冒泡机制从而触发它的外层元素的绑定事件上,然后在外层元素上去执行函数。

委托优点

  1. 省监听数(也就是省内存)
  2. 可以监听动态元素

缺点

调试比较复杂,不容易确定监听者。

实例

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

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

代码: HTML为:

<div id="div1">
  <span>span1</span>
   <button>click 1</button>
   <button>click 2</button>
   <button>click 3</button>
   <button>click 4</button>
   <button>click 5</button>
   <button>click 6</button>//此处有100个`button`
</div>


JavaScript为:

div1.addEventListener('click',(e)=>{
  const t = e.target
  if(t.tagName.toLowerCase()==='button'){
    console.log('button 被点击了')
}})
  • 场景二 你要监听目前不存在的元素的点击事件?

答:监听祖先,等点击的时候看看是不是监听的元素即可。

优点:省监听数(内存),可以动态监听元素 HTML为:

<body>
  <div id=div1>
    
  </div>
</body>


JavaScript为:

setTimeout(()=>{
  const button = document.createElement('button')
  button.textContent='click 1'
  div1.appendChild(button)
},1000)

div1.addEventListener('click',(e)=>{
  const t = e.target
  if(t.tagName.toLowerCase()==='button'){
    console.log('button被click')
  }
})

封装一个事件委托

要求:

  • 写出这样一个函数on('click','#testDiv','li',fn)

  • 当用户点击#testDiv里面的li元素时,调用fn函数

  • 要求用到事件委托

答案1:判断target是否匹配'li'

答案2:target/target的爸爸/target的爷爷

代码: HTML为:

<body>
  <div id=div1>
    
  </div>
</body>


JavaScript为:

setTimeout(()=>{
  const button = document.createElement('button')
  button.textContent='click 1'
  div1.appendChild(button)
},1000)

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)
    }
 })
}

on('click','#div1','button',()=>{
  console.log('button 被点击啦')
})

另一种写法

思路是点击 span 后,递归遍历 span 的祖先元素看其中有没有 ul 里面的 li。

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(ul, 'click', 'li', f1)//点击了ul里面的li