事件委托
事件委托,就是把一个元素响应事件(click、keydown......)的函数委托到另一个元素;
一般来讲,会把一个或者一组元素的事件委托到它的父层或者更外层元素上,真正绑定事件的是外层元素,当事件响应到需要绑定的元素上时,会通过事件冒泡机制从而触发它的外层元素的绑定事件上,然后在外层元素上去执行函数。
委托优点
- 省监听数(也就是省内存)
- 可以监听动态元素
缺点
调试比较复杂,不容易确定监听者。
实例
- 场景一 要给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