1、什么是事件代理
意思:代理、委托。事件代理在JS世界中一个非常有用也很有趣的功能。当我们需要对很多元素添加事件的时候,可以通过将事件添加到它们的父节点而将事件委托给父节点来触发处理函数。
2、运用场景
当子元素被频繁添加或者删除时,给子元素绑定事件,需要在每次添加或者删除时重新绑定,这就造成了非常不方便,那么此时此刻:事件代理,能帮你轻松解决这个麻烦的问题。
3、下面是我实现的一个简单的事件代理方法
1 window.DELEGATE = {};//命名空间 2 /** 3 * 事件处理对象 4 * @type {{addHandler: addHandler, removeHandler: removeHandler}} 5 */ 6 window.DELEGATE.EventUtil = { 7 addHandler: function (element, type, handler) { 8 if (element.addEventListener) { 9 element.addEventListener(type, handler, false); 10 } else if (element.attachEvent) { 11 element.attachEvent("on" + type, handler); 12 } else { 13 element["on" + type] = handler; 14 } 15 }, 16 removeHandler: function(element, type, handler){ 17 if (element.removeEventListener){ 18 element.removeEventListener(type, handler, false); 19 } else if (element.detachEvent){ 20 element.detachEvent("on" + type, handler); 21 } else { 22 element["on" + type] = null; 23 } 24 } 25 }; 26 /** 27 * 比较当前选择于目标函数是否相等 28 * @param element 当前元素 29 * @param selector 目标元素标识 30 */ 31 window.DELEGATE.matchesSelector = function(element, selector){ 32 if(element.matches){ 33 return element.matches(selector); 34 } else if(element.matchesSelector){ 35 return element.matchesSelector(selector); 36 } else if(element.webkitMatchesSelector){ 37 return element.webkitMatchesSelector(selector); 38 } else if(element.msMatchesSelector){ 39 return element.msMatchesSelector(selector); 40 } else if(element.mozMatchesSelector){ 41 return element.mozMatchesSelector(selector); 42 } else if(element.oMatchesSelector){ 43 return element.oMatchesSelector(selector); 44 } else if(element.querySelectorAll){ 45 var matches = (element.document || element.ownerDocument).querySelectorAll(selector), 46 i = 0; 47 while(matches[i] && matches[i] !== element) i++; 48 return matches[i] ? true: false; 49 } 50 throw new Error('Your browser version is too old,please upgrade your browser'); 51 }; 52 53 /** 54 * 缓存所有事件,以数组形式缓存(一个dom上绑定了多个事件时), 55 * 缓存例子为agentObj[e.currentTarget的id,无id用temp++值表示][event][触发事件的tag][] 56 */ 57 window.DELEGATE.agentObj = {}; 58 /** 59 * 用于缓存所有需要触发事件的dom tag, 60 * 缓存例子:selectorObj[e.currentTarget的id,无id用temp++值表示][触发事件的tag][] 61 * 用对象的目的在于方便判断是否已经缓存过了 62 */ 63 window.DELEGATE.selectorObj = {}; 64 /** 65 * 用于e.currentTarget没有id的情况,产生id 66 */ 67 window.DELEGATE.temp = 0; 68 69 /** 70 * 71 * @param parent 父节点id或者父节点元素 72 * @param eventStr 触发事件 73 * @param childTag 触发事件元素标志 74 * @param handler 事件句柄 75 * @constructor 76 */ 77 window.DELEGATE.Delegate = function(parent, eventStr, childTag, handler) { 78 var event = eventStr.toLowerCase(), 79 parentObj = null; 80 if (typeof parent == 'object') { 81 parentObj = 82 parent === document || parent === document.body || parent === document.documentElement ? 83 document.body : 84 parent; 85 if (parentObj.id) { 86 parent = parentObj.id 87 } else { 88 parent = ++window.DELEGATE.temp; 89 } 90 } else { 91 parentObj = document.getElementById(parent); 92 } 93 94 if (!window.DELEGATE.selectorObj[parent]) { 95 window.DELEGATE.selectorObj[parent] = {}; 96 } 97 if (!window.DELEGATE.selectorObj[parent][childTag]) { 98 window.DELEGATE.selectorObj[parent][childTag] = []; 99 } 100 if (!window.DELEGATE.agentObj[parent]) { 101 window.DELEGATE.agentObj[parent] = {}; 102 window.DELEGATE.EventUtil.addHandler(parentObj, event, function (e) { 103 e.stop = false; 104 /** 105 * 阻止冒泡,重置该方法 106 */ 107 e.stopPropagation = function () { 108 e.stop = true; 109 }; 110 var parentElement = e.target; 111 while (parentElement != e.currentTarget && !e.stop) {//从子节点向上冒泡遍历每一个节点与目标节点比较,一直到父节点停止 112 for (var selector in window.DELEGATE.selectorObj[parent]) { 113 if (window.DELEGATE.matchesSelector(parentElement, selector)) { 114 for (var agent in window.DELEGATE.agentObj[parent][eventStr][selector]) { 115 window.DELEGATE.agentObj[parent][eventStr][selector][agent].call(parentElement, e); 116 } 117 } 118 } 119 parentElement = parentElement.parentElement || parentElement.parentNode; 120 } 121 }); 122 } 123 if (!window.DELEGATE.agentObj[parent][eventStr]) { 124 window.DELEGATE.agentObj[parent][eventStr] = {}; 125 } 126 if (!window.DELEGATE.agentObj[parent][eventStr][childTag]) { 127 window.DELEGATE.agentObj[parent][eventStr][childTag] = []; 128 } 129 window.DELEGATE.agentObj[parent][eventStr][childTag].push(handler); 130 131 };
运行demo:http://runjs.cn/detail/iaz5oole
关于事件代理还有很多东西可以深入学习和研究,希望大家给我支持,多留言,一起讨论,共同进步,谢谢!!!