2020-09-07-event-listener

134 阅读2分钟

了解相关概念

  • 1.什么是事件代理?

事件委托或事件代理:根据红宝书来说:就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。举例:dom需要事件处理程序,我们都会直接给它设置事件处理程序。但是在ul中1000个li全部需要添加事件处理程序,其具有相同的点击事件,那么可以根据for来进行遍历,也可以在ul上来进行添加。在性能的角度上来看,在ul建立事件会减少dom的交互次数,提高性能。

2.事件代理原理

事件委托就是利用事件的冒泡原理来实现的,就是事件从最深的节点开始,然后逐步向上传播事件。

举例:页面上有这么一个节点树,div>ul>li>a;比如给最里面的a加一个click点击事件,那么这个事件就会一层一层的往外执行,执行顺序a>li>ul>div,有这样一个机制,那么我们给最外面的div加点击事件,那么里面的ul、li、a做点击事件的时候,都会冒泡到最外层的div上,所以都会触发,这就是事件委托,委托它们父级代为执行事件

代码实现
  • 1.实现ul中li的事件代理
window.onload=function(){
    var oBtn=document.getElementById('btn');
    var oUl=document.getElementById('ul1');
    var aLi=oUl.getElementsByTagName('li');
    var num=4;
    //事件委托,添加的子元素也有事件
    oUl.onmouseover=function(e){
        var e=e||window.event;
        var target=e.target||e.srcElement;
        if(target.nodeName.toLowerCase()==='li'){
            target.style.background="red";
        }
    };
    oUl.onmouseout=function(e){
        var e=e||window.event;
        var target=e.target||e.srcElement;
        if(target.nodeName.toLowerCase()==='li'){
            target.style.background="blue"
        }
    };
    //添加新节点
    oBtn.onclick=function(){
        num++;
        var oLi=document.createElement('li');
        oLi.innerHTML=111*num;
        oUl.appendChild(oLi)
    };
}
  • 2.简单封装一个事件代理通用代码
!function(root,doc){
    class Delegator(selector){
        this.root=document.querySelector(selector);//父级dom
        this.delegatorEvents={}//代理元素及事件
        //代理逻辑
        this.delegator=e=>{
            let currentNode=e.target//目标节点
            const targetEventList=this.delegatorEvents[e.type];
            //如果当前目标节点等于事件目前所在的节点,不再往上冒泡
            while(currentNode !== e.currentTarget){
                targetEventList.forEach(target=>{
                    if(currentNode.matches(target.matcher)){
                        //开始委托并把当前目标节点的event对象传过去
                        target.callback.call(currentNode,e)
                    }
                })
                currentNode=currentNode.parentNode;
            }
        }
    }
    //绑定事件  event---绑定事件类型  selector---需要被代理的选择器  fn---触发函数
    on(event,selector,fn){
        //相同事件只能添加一次,如果存在,则在对应的代理事件里添加
        if(!this.delegatorEvents[event]){
            this.delegatorEvents[event]=[{
                matcher:selector,
                callback:fn
            }]
            this.root.addEventListener(event,this.delegator)
        }else{
            this.delegatorEvents[event].push({
                matcher:seletor,
                callback:fn
            })
        }
        return this;
    }
    // 移除事件
    destory(){
        Object.keys(this.delegatorEvents).forEach(eventName=>{
            this.root.removeEventListener(eventName,this.delegator)
        })
    }
    root.Delegator=Delegator;
}(window,document)