什么是事件委托?
事件委托是一种设计模式,它利用了事件冒泡的机制。当一个元素上的事件被触发时,它会向上冒泡传递至父级元素,直到元素的最顶层。
事件冒泡就是说当某个特定类型的事件(比如点击事件)在最内层的元素上触发时,这个事件会从内层元素开始逐级向外传播,直到传播到最外层的元素为止。换句话说,事件会从触发元素开始,逐级向上冒泡至文档树的根节点。
当鼠标单击div1的时候,事件会向外传递到div2、div3,一直延伸到body,最终到达window,只要在对应的元素上设置了点击事件,该事件就会触发,并且按照冒泡的顺序依次传递到父级元素。
案例
现在需要div点击的时候,缩小自己的宽和高,每次缩小到自己的百分之90,下面是效果
这个要如何实现呢?
第一个想到的方案是每个元素添加点击事件,并阻止事件冒泡
const div1 = document.querySelector('.div1')
const div2 = document.querySelector('.div2')
const div3 = document.querySelector('.div3')
div1.addEventListener('click', (e) => {
div1.style.width = parseInt(window.getComputedStyle(div1).width) * 0.9 + 'px'
div1.style.height = parseInt(window.getComputedStyle(div1).height) * 0.9 + 'px'
e.stopPropagation() //阻止冒泡
})
div2.addEventListener('click', (e) => {
div2.style.width = parseInt(window.getComputedStyle(div2).width) * 0.9 + 'px'
div2.style.height = parseInt(window.getComputedStyle(div2).height) * 0.9 + 'px'
e.stopPropagation() //阻止冒泡
})
div3.addEventListener('click', (e) => {
div3.style.width = parseInt(window.getComputedStyle(div3).width) * 0.9 + 'px'
div3.style.height = parseInt(window.getComputedStyle(div3).height) * 0.9 + 'px'
e.stopPropagation() //阻止冒泡
})
这样写显得代码冗余了很多,三个触发的效果是一样的,还不如只定义一个点击事件呢
const div1 = document.querySelector('.div1')
const div2 = document.querySelector('.div2')
const div3 = document.querySelector('.div3')
function changeSize(e) {
e.target.style.width = parseInt(window.getComputedStyle(e.target).width) * 0.9 + 'px'
e.target.style.height = parseInt(window.getComputedStyle(e.target).height) * 0.9 + 'px'
e.stopPropagation()
}
div1.addEventListener('click',changeSize)
div2.addEventListener('click',changeSize)
div3.addEventListener('click',changeSize)
e.target的意思就是哪个元素触发了事件,哪个元素就是e.target。
那能不能在简洁一点呢? 我们现在就来看一下事件委托是如何实现的,当div1,div2点击到的时候,冒泡到div3上,只给div3做个点击事件,是不是也可以呢?
const div3 = document.querySelector('.div3')
div3.addEventListener('click', (e) => {
e.target.style.width = parseInt(window.getComputedStyle(e.target).width) * 0.9 + 'px'
e.target.style.height = parseInt(window.getComputedStyle(e.target).height) * 0.9 + 'px'
e.stopPropagation()
})
这种操作就叫做事件委托,如果用的熟练的话,可以大幅缩短代码量,提升工作效率。
但是呢,事物都是有两面性的,事件委托也有它的优缺点。
优点
● 减少事件处理程序的数量:通过将事件绑定在父元素上,可以避免给每个子元素都添加事件处理程序。这在处理大量元素时可以显著减少代码的复杂性和维护成本。
● 动态添加元素支持:对于后续动态添加的子元素,无需单独为它们添加事件处理程序,因为事件委托是基于父元素的,新添加的元素也会受到委托的处理。
● 内存和性能优化:事件委托利用事件冒泡的特性,将事件处理放在父元素上,避免了在每个子元素上都绑定事件,从而节省内存和提高性能。
● 方便绑定动态元素:当页面中存在大量元素时,事件委托可以方便地处理动态添加的元素,无需为新元素单独添加事件监听。
缺点
● 事件冒泡带来的潜在问题:由于事件冒泡的特性,事件委托可能导致事件在父元素上被多次触发,这可能会影响性能和产生不良影响。为了避免这个问题,需要在事件处理程序中正确判断事件源。
● 不适用于所有情况:并非所有事件都适合使用事件委托。例如,如果需要在不同阶层的元素上绑定不同的事件处理程序,或者需要对事件进行捕获阶段的处理,事件委托可能无法满足需求。
● 事件目标确定:在事件委托中,需要通过事件对象的target属性来确定真正的事件目标,这可能会涉及到一些复杂的逻辑。
当处理大量元素的事件处理时候,事件委托是一个强大的功能,可以提高代码效率,减少内存占用,方便的处理添加的元素,当然,也必须要避免潜在的问题,以确保事件委托的正确用法。