我们收取快递有两种方法:一是在特定的地点等快递的到来,二是委托人代收。现实当中,我们大都采用委托的方案。而委托人接受的委托不止一份,他会判断收件人,从而发放到各自手中。这也就是js事件委托的通俗理解。
为啥要用事件委托?
一般来说,dom需要有事件处理程序,我们都会直接给它设事件处理程序就好了,那为什么要用事件委托呢?
独立典型的程序或许需要单独的处理程序,但是程序的结构越复杂庞大,就会有大量重复的程序事件。单独直接得处理程序,会严重影响工作的效率。可能,我们能用for循环等方法,遍历所以程序,但这会导致与dom节点的不断交互,访问dom的次数越多,引起浏览器重绘与重排的次数也就越多,就会延长整个页面的交互就绪时间,这就是为什么性能优化的主要思想之一就是减少DOM操作的原因。
所以如果要用事件委托,就会将所有的操作放到js程序里面,与dom的操作就只需要交互一次,这样就能大大的减少与dom的交互次数,提高性能
如何实现事件委托?
事件委托是利用事件的冒泡原理来实现的事件从最深的节点开始,然后逐步向上传播至最上层的事件。
网上常见的例子
<ul id="ul">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
我们需要把li的点击事件绑定到ul上
var ul = document.getElementById('ul')
ul.addEventListener('click', function() {})
这样我们就实现了委托,但是有出现了新的问题,如果ul内不止li,那么处于ul内的其他元素被点击时,事件也被触发了!
所以我们需要在触发事件前来一个判断
ul.addEventListener('click', function(e)
// 检查事件源e.targe是否为Li
if (e.target && e.target.nodeName.toUpperCase == "LI") {
// 真正的处理过程在这里
console.log("点击成功")
}
}
这样就大功告成了?很遗憾,这种情况还存在一个严重的bug,如果元素在li中呢?那么事件就不会触发!比如这样
<ul id="ul">
<li id="l1"><span>1</span></li>
<li id="l2">2</li>
<li id="l3">3</li>
<li id="l4">4</li>
</ul>
那么该怎么做呢?我们需要再加一个判断,判断点击的元素的父辈元素中有没有li,如果有,就继续执行事件。
ul.addEventListener('click', function() {
let el = e.target
while (el && !el.matches(selector)) {
el = el.parentNode
if (element === el) {
el = null
}
}
if (el) {
console.log('执行回调函数')
}
}
后记
我们发现问题,然后找出方法解决问题。并不代表事件的结束,我们所用的方法也许会带来其他的原题。多思考,多测试,不断完善。记住,现在得到的永远不是最佳答案。
网友评论