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