js的事件代理_事件代理和事件绑定
未分类
2023-01-16
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方式(用于注销事件)
此代码由Java架构师必看网-架构君整理!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.新添加元素也能够响应绑定;
此代码由Java架构师必看网-架构君整理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)