JS事件委托(事件代理)
什么是事件委托?
举个例子,我们要实现点击 li 时打印其id
<ul id="myList">
<li id="a">aaa</li>
<li id="b">bbb</li>
<li id="c">ccc</li>
</ul>
一般我们会给每一个li绑定一个事件处理函数
let myList = document.getElementById('myList')
let oLi = myList.getElementsByTagName('li')
for (let i = 0; i < oLi.length; i++ ) {
oLi[i].addEventListener('click', function () {
console.log(this.id)
})
}
这种方法存在两个问题:
- 如果有很多 li,大量的事件处理程序会占用不少内存,绑定事件处理程序也需要访问很多次DOM,页面的整体性能将大大降低
- 后续新增的li没有绑定事件处理程序
事件委托就是解决这两个问题的一种方案,方式如下
let myList = document.getElementById('myList')
myList.addEventListener('click', function (e) {
console.log(e.target.id)
})
事件委托的原理:
由于事件冒泡的机制,当我们点击li时,ul也会触发click事件,所以我们只需给ul绑定事件处理程序,就能监听所有li的click事件,而且是动态的,新增的li也能被监听;
但如何判断我们点击的是哪个 li 呢?Event对象提供了一个属性叫target,该属性包含事件的目标,也就是事件源,通过target可以得到事件的目标节点
常见的问题
1.如果每个li被点击的效果不一样,怎么办呢?
let myList = document.getElementById('myList');
myList.addEventListener('click', function (e) {
let target = e.target
if (target.nodeName.toLowerCase() === 'li') {
switch(target.id) {
case 'a':
console.log('a1');
break;
case 'b':
console.log('b2');
break;
case 'c':
console.log('c3');
break;
}
}
})
2.如果li还有其他子节点怎么办?
<ul id="myList">
<li id="a">
<p>aaa</p>
</li>
<li id="b">
<div>
<p>bbb</p>
</div>
</li>
<li id="c">ccc</li>
</ul>
let myList = document.getElementById('myList');
myList.addEventListener('click', function (e) {
let target = e.target
while (target !== myList) {
if (target.tagName.toLowerCase() === 'li') {
console.log(target.id)
break
}
target = target.parentNode
}
})
核心是通过while和target.parentNode(或parentElement)遍历事件流上的所有节点
JQuery的事件委托
$('#myList').on('click', 'li', function (e) {
console.log(e.currentTarget.id)
console.log(this.id)
})
on()方法语法如下
$(selector).on(event,childSelector,data,function)
childSelector:指定被代理的后代元素
这里的this和e.currentTarget指向childSelector
React 与 Vue 中是否有必要使用事件委托?
React 内部自定义了一套事件系统,利用事件委托机制在Document上统一监听DOM事件,再根据触发的target将事件分发到具体的组件实例,所以无需我们再使用事件委托
Vue 内部没有做事件委托,但做了一些优化,在 v-for 中每个侦听器都使用同一个回调,并会自动处理监听器的创建和销毁,所以一般情况下没有必要使用事件委托
参考:
js中的事件委托或是事件代理详解 - 凌云之翼 - 博客园
谈谈React事件机制和未来(react-events) - 荒山的文章 - 知乎
https://www.runoob.com/jquery/event-on.html
https://forum.vuejs.org/t/is-event-delegation-necessary/3701/3
《JavaScript高级程序设计》