事件委托

475 阅读2分钟

事件委托

我们在网页编程中,少不了进行事件监听,一般我们会使用 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,不指向调用者