事件委托
我们在网页编程中,少不了进行事件监听,一般我们会使用 onClick 或者 addEveentListener,前者注册事件会被覆盖,而后者可以无限注册事件,还可以控制事件触发的阶段,默认为冒泡阶段触发事件
假设我们想要监听一个列表子元素的新增,新增一个列表后,我们要去请求相应的数据,第一个问题是我们不知道什么时候会添加,因为这是用户的操作;第二这个列表可能会有很多,如果给每一个元素都添加监听,那么页面上会同时存在很多事件,于是我们写出以下代码
//假设事件为点击类型
element.addEventListener('click',(e)=>{
let el=e.target
if(el.tagName.toLowerCase()==='li'){
...
}
})
看起来没什么问题,功能也是正常的,但是实际情况远远比以上复杂,li 中可能还有多个标签,那么我们点击最深处的标签,由于事件冒泡,也应该触发事件,但是按照以上代码缺无法做到,应该进行递归判断,那就改进一下我们的代码
function delegate(element,eventType,selector,fn){
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)
})
return element
}
第一个参数是外层元素,第二个是事件类型,第三个是第一个元素的选择器,第四个是回调 ,思路就是递归判断
看完后大家可能会想,这个逻辑不合理呀,如果 el 不匹配选择器的话,element 怎么可能和 el 相等呢,你这不是多此一举嘛
这其实是一个错误处理,假如我们传错了 selector,就说明 while 的判断结果永远都为真,那就不会结束循环,也就不会执行回调
注意在书写回调函数时,最好使用普通匿名函数的写法,如果写成箭头函数,其中的 this 将指向上一层作用域的 this,不指向调用者