js事件代理(委托)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了js事件代理(委托)相关的知识,希望对你有一定的参考价值。
javascript事件代理(委托)一般用于以下情况:
1. 事件注册在祖先级元素上,代理其子级元素。可以减少事件注册数量,节约内存开销,提高性能。
2. 对js动态添加的子元素可自动绑定事件。
之前一直用各种js库的事件代理,如 jQuery,非常方便实用。今天尝试用原生 js 实现该功能。
1 var addEvent = (function () { 2 if (document.addEventListener) { 3 return function (element, type, handler) { 4 element.addEventListener(type, handler, false); 5 }; 6 } else if (document.attachEvent) { 7 return function (element, type, handler) { 8 element.attachEvent(‘on‘ + type, function () { 9 handler.apply(element, arguments); 10 }); 11 }; 12 } else { 13 return function (element, type, handler) { 14 element[‘on‘ + type] = function (event) { 15 return handler.apply(element, arguments); 16 }; 17 }; 18 } 19 })(), 20 21 getClassElements = function (parentElement, classname) { 22 var all, element, classArr = [], classElements = []; 23 24 if (parentElement.getElementsByClassName) { 25 return parentElement.getElementsByClassName(classname); 26 } else { 27 all = parentElement.getElementsByTagName(‘*‘); 28 29 for (var i = 0, len = all.length; i < len; i++) { 30 element = all[i]; 31 classArr = element && element.className && element.className.split(‘ ‘); 32 33 if (classArr) { 34 for (var j = 0; j < classArr.length; j++) { 35 if (classArr[j] === classname) { 36 classElements.push(element); 37 } 38 } 39 } 40 } 41 42 return classElements; 43 } 44 }, 45 46 delegate = function () { // 参数:element, type, [selector,] handler 47 var args = arguments, 48 element = args[0], 49 type = args[1], 50 handler; 51 52 if (args.length === 3) { 53 handler = args[2]; 54 return addEvent(element, type, handler); 55 } 56 57 if (args.length === 4) { 58 selector = args[2]; 59 handler = args[3]; 60 61 return addEvent(element, type, function (event) { 62 var event = event || window.event, 63 target = event.target || event.srcElement, 64 quickExpr = /^(?:[a-zA-Z]*#([\w-]+)|(\w+)|[a-zA-Z]*\.([\w-]+))$/, 65 match, 66 idElement, 67 elements, 68 tagName, 69 count = 0, 70 len; 71 72 if (typeof selector === ‘string‘) { 73 match = quickExpr.exec(selector); 74 75 if (match) { 76 // #ID selector 77 if (match[1]) { 78 idElement = document.getElementById(match[1]); 79 tagName = match[0].slice(0, match[0].indexOf(‘#‘)); 80 81 // tag selector 82 } else if (match[2]) { 83 elements = element.getElementsByTagName(selector); 84 85 // .class selector 86 } else if (match[3]) { 87 elements = getClassElements(element, match[3]); 88 tagName = match[0].slice(0, match[0].indexOf(‘.‘)); 89 } 90 } 91 92 if (idElement) { 93 if ( target === idElement && (tagName ? idElement.nodeName.toLowerCase() === tagName : true) ) { 94 return handler.apply(idElement, arguments); 95 } 96 } else if (elements) { 97 for (len = elements.length; count < len; count++) { 98 if ( target === elements[count] && (tagName ? elements[count].nodeName.toLowerCase() === tagName : true) ) { 99 return handler.apply(elements[count], arguments); 100 } 101 } 102 } 103 } 104 }); 105 } 106 };
主要是用 apply 改变 this 的指向
handler.apply(idElement, arguments);
handler.apply(elements[count], arguments);
测试一下:
<style> #outer {padding: 50px; background-color: lightpink;} #inner {padding: 30px; background-color: aliceblue;} #paragraph1, #paragraph3 {background-color: cadetblue} </style>
<div id="outer">outer <div id="inner">inner <p id="paragraph1" class="parag1">paragraph1</p> <p id="paragraph2" class="parag">paragraph2</p> <span>span</span> <p id="paragraph3" class="parag">paragraph3</p> </div> </div>
var outer = document.getElementById(‘outer‘); delegate(outer, ‘click‘, function () { console.log(this.id); // outer });
delegate(outer, ‘click‘, ‘p‘, function () { console.log(this.id); //点击 paragraph1 元素,输出其id为 "paragraph1" });
模仿 jQuery 的风格,优化代码:
1 (function () { 2 var $ = function (element) { 3 return new _$(element); 4 }; 5 6 var _$ = function (element) { 7 this.element = element && element.nodeType === 1 ? element : document; 8 }; 9 10 _$.prototype = { 11 constructor: _$, 12 13 addEvent: function (type, handler, useCapture) { 14 var element = this.element; 15 16 if (document.addEventListener) { 17 element.addEventListener(type, handler, (useCapture ? useCapture : false)); 18 } else if (document.attachEvent) { 19 element.attachEvent(‘on‘ + type, function () { 20 handler.apply(element, arguments); 21 }); 22 } else { 23 element[‘on‘ + type] = function (event) { 24 return handler.apply(element, arguments); 25 }; 26 } 27 28 return this; 29 }, 30 31 getClassElements: function (classname) { 32 var element = this.element, all, ele, classArr = [], classElements = []; 33 34 if (element.getElementsByClassName) { 35 return element.getElementsByClassName(classname); 36 } else { 37 all = element.getElementsByTagName(‘*‘); 38 39 for (var i = 0, len = all.length; i < len; i++) { 40 ele = all[i]; 41 classArr = ele && ele.className && ele.className.split(‘ ‘); 42 43 if (classArr) { 44 for (var j = 0; j < classArr.length; j++) { 45 if (classArr[j] === classname) { 46 classElements.push(ele); 47 } 48 } 49 } 50 } 51 52 return classElements; 53 } 54 }, 55 56 delegate: function () { //参数:type, [selector,] handler 57 var self = this, 58 element = this.element, 59 type = arguments[0], 60 handler; 61 62 if (arguments.length === 2) { 63 handler = arguments[1]; 64 return self.addEvent(type, handler); 65 } else if (arguments.length === 3) { 66 selector = arguments[1]; 67 handler = arguments[2]; 68 69 return self.addEvent(type, function (event) { 70 var event = event || window.event, 71 target = event.target || event.srcElement, 72 quickExpr = /^(?:[a-zA-Z]*#([\w-]+)|(\w+)|[a-zA-Z]*\.([\w-]+))$/, 73 match, 74 idElement, 75 elements, 76 tagName, 77 count = 0, 78 len; 79 80 if (typeof selector === ‘string‘) { 81 match = quickExpr.exec(selector); 82 83 if (match) { 84 // #ID selector 85 if (match[1]) { 86 idElement = document.getElementById(match[1]); 87 tagName = match[0].slice(0, match[0].indexOf(‘#‘)); 88 89 // tag selector 90 } else if (match[2]) { 91 elements = element.getElementsByTagName(selector); 92 93 // .class selector 94 } else if (match[3]) { 95 elements = self.getClassElements(match[3]); 96 tagName = match[0].slice(0, match[0].indexOf(‘.‘)); 97 } 98 } 99 100 if (idElement) { 101 if ( target === idElement && (tagName ? idElement.nodeName.toLowerCase() === tagName : true) ) { 102 return handler.apply(idElement, arguments); 103 } 104 } else if (elements) { 105 for (len = elements.length; count < len; count++) { 106 if ( target === elements[count] && (tagName ? elements[count].nodeName.toLowerCase() === tagName : true) ) { 107 return handler.apply(elements[count], arguments); 108 } 109 } 110 } 111 } 112 }); 113 } 114 } 115 }; 116 117 window.$ = $; 118 return $; 119 }());
使用如下:
var outer = document.getElementById(‘outer‘); $(outer).delegate(‘click‘, ‘.parag‘, function (event) { console.log(this.id); });
以上是关于js事件代理(委托)的主要内容,如果未能解决你的问题,请参考以下文章