一、事件委托定义
-
在
JavaScript
中,添加到页面上的事件处理程序数量将直接关系到页面的整体运行性能。导致这一问题的原因是多方面的。首先,每个函数都是对象,都会占用内存;内存中的对象越多,性能就越差。其次,必须事先指定所有事件处理程序而导致的DOM
访问次数,会延迟整个页面的交互就绪时间。 -
捕获和冒泡允许我们实现一种被称为 事件委托 的强大的事件处理模式。对事件处理程序过多问题的解决方案就是事件委托。事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。这个想法是,如果我们有许多以类似方式处理的元素,那么就不必为每个元素分配一个处理程序 —— 而是将单个处理程序放在它们的共同祖先上。例如,
click
事件会一直冒泡到document
层次。也就是说,我们可以为整个页面指定一个onclick
事件处理程序,而不必给每个可单击的元素分别添加事件处理程序 — —简而言之,把本该这个元素做的事情,全部委托给共同祖先,让祖上处理。 -
优点:提高页面性能,可以监听动态元素
-
在处理程序中,我们获取 event.target 以查看事件实际发生的位置并进行处理。
二、封装事件委托
写出一个函数,例如on(‘click’, ‘#div1’,‘li’, fn),当用户点击div1中的li时,调用fn函数
// 答案一
setTimeout(()=>{
const button = document.createElement('button')
button.textContent= 'click 1'
div1.appendChild(button)
},1000)
functin 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 被点击了')
})
// 答案二: 使用递归进行判断
function on(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
注意的是:本章节讲的是DOM
的事件,JS
只是调用了DOM
提供的addEventListener
方法,其实JS
不支持事件,除非开发者手写一个事件系统