JS手动实现事件代理

JS手动实现事件代理简介由于事件在冒泡阶段向上传播到父节点,因此可以把子节点监听的事件在父节点的监听,由父节点的监听函数统一处理多个子元素的的事件,这种方法就叫做事件的代理,处理如下:varul=document.querySelector(‘ul’);ul.addEventListener(‘click’,function(event){if(event.target.tagName.t…

简介

由于事件在冒泡阶段向上传播到父节点,因此可以把子节点监听的事件在父节点的监听,由父节点的监听函数统一处理多个子元素的的事件,这种方法就叫做事件的代理,处理如下:

var ul = document.querySelector('ul');

ul.addEventListener('click', function (event) { 
   
  if (event.target.tagName.toLowerCase() === 'li') { 
   
    // some code
  }
});

这样做的好处:

只需在父节点定义一个监听函数,就可以统一处理子节点的事件了;
动态添加子节点,也可以监听到;

下面呢?我们就手动实现下事件代理

实现步骤

创建一个Delegator类,定义一个on方法(监听),再定义一个destroy方式(用于注销事件)

!function (root, doc) { 
   

  class Delegator { 
   
    /* *@param 顶级选择器(代理者) */
    constructor (selector) { 
   

    }
    /* *绑定事件 *@param event 绑定事件类型 *@param selector 需要被代理的选择器 *@param fn 触发函数 * */
    on (event, selector, fn) { 
   

    }
    /* *移除事件 */
    destroy () { 
   
   
    }
  }

  root.Delegator = Delegator
}(window, document)

定义两个实例属性,分别用来接受root节点和被代理的元素对象。

 constructor (selector) { 
   
      this.root = document.querySelector(selector);//顶级dom
      this.delegatorEvents = { 
   //代理元素及事件
      	//evenType:[{ 
   
			//matcher:selector,//元素dom节点
			//callback:fn,//事件函数
	    }]
	  };
    }

绑定事件具体逻辑

1.事件代理触发顺序满足冒泡规则;;
2.this 应当指向正确的元素;
3.相同事件只做一个监听
4.新添加元素也能够响应绑定;

   constructor (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对象传过去,改为this指向
              target.callback.call(currentNode, e);
            }
          })
          currentNode = currentNode.parentNode;
        }
      }
    }
    /* *绑定事件 *@param event 绑定事件类型 *@param selector 需要被代理的选择器 *@param 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: selector,
          callback: fn
        })
      }
      return this;
    }

注销事件

    /* *移除事件 */
    destroy () { 
   
      Object.keys(this.delegatorEvents).forEach(eventName => { 
   
        this.root.removeEventListener(eventName, this.delegator)
      });
    }

全部代码

!function (root, doc) { 
   

  class Delegator { 
   
    /* *@param 顶级选择器(代理者) */
    constructor (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;
        }
      }
    }
    /* *绑定事件 *@param event 绑定事件类型 *@param selector 需要被代理的选择器 *@param 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: selector,
          callback: fn
        })
      }
      return this;
    }
    /* *移除事件 */
    destroy () { 
   
      Object.keys(this.delegatorEvents).forEach(eventName => { 
   
        this.root.removeEventListener(eventName, this.delegator)
      });
    }
  }

  root.Delegator = Delegator
}(window, document)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/11997.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注