浅谈事件代理

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

关于事件代理还有很多东西可以深入学习和研究,希望大家给我支持,多留言,一起讨论,共同进步,谢谢!!!

原文地址:https://www.cnblogs.com/bo-haier/p/5644731.html