您的位置:首页 > 其它

浅谈事件代理

2016-07-05 23:59 162 查看
1、什么是事件代理

意思:代理、委托。事件代理在JS世界中一个非常有用也很有趣的功能。当我们需要对很多元素添加事件的时候,可以通过将事件添加到它们的父节点而将事件委托给父节点来触发处理函数。

2、运用场景

当子元素被频繁添加或者删除时,给子元素绑定事件,需要在每次添加或者删除时重新绑定,这就造成了非常不方便,那么此时此刻:事件代理,能帮你轻松解决这个麻烦的问题。

3、下面是我实现的一个简单的事件代理方法

window.DELEGATE = {};//命名空间
/**
* 事件处理对象
* @type {{addHandler: addHandler, removeHandler: removeHandler}}
*/
window.DELEGATE.EventUtil = {
addHandler: function (element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else if (element.attachEvent) {
element.attachEvent("on" + type, handler);
} else {
element["on" + type] = handler;
}
},
removeHandler: function(element, type, handler){
if (element.removeEventListener){
element.removeEventListener(type, handler, false);
} else if (element.detachEvent){
element.detachEvent("on" + type, handler);
} else {
element["on" + type] = null;
}
}
};
/**
* 比较当前选择于目标函数是否相等
* @param element 当前元素
* @param selector 目标元素标识
*/
window.DELEGATE.matchesSelector = function(element, selector){
if(element.matches){
return element.matches(selector);
} else if(element.matchesSelector){
return element.matchesSelector(selector);
} else if(element.webkitMatchesSelector){
return element.webkitMatchesSelector(selector);
} else if(element.msMatchesSelector){
return element.msMatchesSelector(selector);
} else if(element.mozMatchesSelector){
return element.mozMatchesSelector(selector);
} else if(element.oMatchesSelector){
return element.oMatchesSelector(selector);
} else if(element.querySelectorAll){
var matches = (element.document || element.ownerDocument).querySelectorAll(selector),
i = 0;
while(matches[i] && matches[i] !== element) i++;
return matches[i] ? true: false;
}
throw new Error('Your browser version is too old,please upgrade your browser');
};

/**
* 缓存所有事件,以数组形式缓存(一个dom上绑定了多个事件时),
* 缓存例子为agentObj[e.currentTarget的id,无id用temp++值表示][event][触发事件的tag][]
*/
window.DELEGATE.agentObj = {};
/**
* 用于缓存所有需要触发事件的dom tag,
* 缓存例子:selectorObj[e.currentTarget的id,无id用temp++值表示][触发事件的tag][]
* 用对象的目的在于方便判断是否已经缓存过了
*/
window.DELEGATE.selectorObj = {};
/**
* 用于e.currentTarget没有id的情况,产生id
*/
window.DELEGATE.temp = 0;

/**
*
* @param parent 父节点id或者父节点元素
* @param eventStr 触发事件
* @param childTag 触发事件元素标志
* @param handler 事件句柄
* @constructor
*/
window.DELEGATE.Delegate  = function(parent, eventStr, childTag, handler) {
var event = eventStr.toLowerCase(),
parentObj = null;
if (typeof parent == 'object') {
parentObj =
parent === document || parent === document.body || parent === document.documentElement ?
document.body :
parent;
if (parentObj.id) {
parent = parentObj.id
} else {
parent = ++window.DELEGATE.temp;
}
} else {
parentObj = document.getElementById(parent);
}

if (!window.DELEGATE.selectorObj[parent]) {
window.DELEGATE.selectorObj[parent] = {};
}
if (!window.DELEGATE.selectorObj[parent][childTag]) {
window.DELEGATE.selectorObj[parent][childTag] = [];
}
if (!window.DELEGATE.agentObj[parent]) {
window.DELEGATE.agentObj[parent] = {};
window.DELEGATE.EventUtil.addHandler(parentObj, event, function (e) {
e.stop = false;
/**
* 阻止冒泡,重置该方法
*/
e.stopPropagation = function () {
e.stop = true;
};
var parentElement = e.target;
while (parentElement != e.currentTarget && !e.stop) {//从子节点向上冒泡遍历每一个节点与目标节点比较,一直到父节点停止
for (var selector in window.DELEGATE.selectorObj[parent]) {
if (window.DELEGATE.matchesSelector(parentElement, selector)) {
for (var agent in window.DELEGATE.agentObj[parent][eventStr][selector]) {
window.DELEGATE.agentObj[parent][eventStr][selector][agent].call(parentElement, e);
}
}
}
parentElement = parentElement.parentElement || parentElement.parentNode;
}
});
}
if (!window.DELEGATE.agentObj[parent][eventStr]) {
window.DELEGATE.agentObj[parent][eventStr] = {};
}
if (!window.DELEGATE.agentObj[parent][eventStr][childTag]) {
window.DELEGATE.agentObj[parent][eventStr][childTag] = [];
}
window.DELEGATE.agentObj[parent][eventStr][childTag].push(handler);

};


运行demo:http://runjs.cn/detail/iaz5oole

关于事件代理还有很多东西可以深入学习和研究,希望大家给我支持,多留言,一起讨论,共同进步,谢谢!!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: