由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件。
1. 使用场景
- 给多个按钮添加点击事件
- 监听目前还没创建出来的元素的点击事件
第一个场景,可以监听这100个按钮的父层或者更外层元素,等冒泡阶段的时候判断target是不是这100个按钮中的一个。
第二个场景,监听父层或者更外层元素,等点击的时候看看是否是自己想要监听的元素
使用事件委托的好处:
- 不需要为每个事件创建监听器,省内存
- 可以动态的监听元素
2. 封装事件委托
on('click','#div1','button',()=>{
console.log('button 被点击')
})
function on(eventType,element,seletor,fn){
if(!(element instanceof Element)){
element = document.querySelector(element)
}
element.addEventListener(eventType,(e)=>{
const t = e.target
if(t.matches(selector)){
fn(e)
}
})
}
以上的例子就是一个封装好的事件委托函数,接下来只要用点击button,就会执行on。
思路:给元素添加一个监听,接下来判断当前的target是否满足selector,如果满足就调用函数,不满足就跳过。
**注意:这种方法,在某些情况下时会失效,当button里还有span元素时,事件监听就会失效。**因为当前的target已经由button变为span,所以会失效。
function(eventType,element, selector, fn) {
if(!(element instanceof Element)){
element = document.querySelector(element)
}
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
},
把代码改成上面的就是最终形态,完美的事件委托。
思路:首先看被操作的元素是否满足button,不符合的话就让该元素等于他的父元素,当找到他的最顶层元素还没找到,就当找不到了,直接结束。如果找到一个父元素匹配选择器,那么事件成立,直接调用函数fn