欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

详解js的事件代理(委托)

程序员文章站 2023-09-29 10:53:21
javascript事件代理(委托)一般用于以下情况:   1. 事件注册在祖先级元素上,代理其子级元素。可以减少事件注册数量,节约内存开销,提高性能。 &n...

javascript事件代理(委托)一般用于以下情况:

  1. 事件注册在祖先级元素上,代理其子级元素。可以减少事件注册数量,节约内存开销,提高性能。

  2. 对js动态添加的子元素可自动绑定事件。

之前一直用各种js库的事件代理,如 jquery,非常方便实用。今天尝试用原生 js 实现该功能。

var addevent = (function () {
 if (document.addeventlistener) {
 return function (element, type, handler) {
 element.addeventlistener(type, handler, false);
 };
 } else if (document.attachevent) {
 return function (element, type, handler) {
 element.attachevent('on' + type, function () {
 handler.apply(element, arguments);
 });
 };
 } else {
 return function (element, type, handler) {
 element['on' + type] = function () {
 return handler.apply(element, arguments);
 };
 };
 }
})(),
getclasselements = function (parentelement, classname) {
 var all, element, classarr = [], classelements = [];
 if (parentelement.getelementsbyclassname) {
 return parentelement.getelementsbyclassname(classname);
 } else {
 all = parentelement.getelementsbytagname('*');
 for (var i = 0, len = all.length; i < len; i++) {
 element = all[i];
 classarr = element && element.classname && element.classname.split(' ');
 if (classarr) {
 for (var j = 0; j < classarr.length; j++) {
  if (classarr[j] === classname) {
  classelements.push(element);
  }
 }
 }
 }
 return classelements;
 }
},
delegate = function () { // 参数:element, type, [selector,] handler
 var args = arguments,
 element = args[0],
 type = args[1],
 handler;
 if (args.length === 3) {
 handler = args[2];
 return addevent(element, type, handler);
 }
 if (args.length === 4) {
 selector = args[2];
 handler = args[3];
 return addevent(element, type, function (event) {
 var event = event || window.event,
 target = event.target || event.srcelement,
 quickexpr = /^(?:[a-za-z]*#([\w-]+)|(\w+)|[a-za-z]*\.([\w-]+))$/,
 match,
 idelement,
 elements,
 tagname,
 count = 0,
 len;
 if (typeof selector === 'string') {
 match = quickexpr.exec(selector);
 if (match) {
  // #id selector
  if (match[1]) {
  idelement = document.getelementbyid(match[1]);
  tagname = match[0].slice(0, match[0].indexof('#'));
  // tag selector
  } else if (match[2]) {
  elements = element.getelementsbytagname(selector);
  // .class selector
  } else if (match[3]) {
  elements = getclasselements(element, match[3]);
  tagname = match[0].slice(0, match[0].indexof('.'));
  }
 }
 if (idelement) {
  if ( tagname ? tagname === idelement.nodename.tolowercase() && target === idelement : target === idelement ) {
  return handler.apply(idelement, arguments);
  }
 } else if (elements) {
  for (len = elements.length; count < len; count++) {
  if ( tagname ? tagname === elements[count].nodename.tolowercase() && target === elements[count] : target === elements[count] ) {
  return handler.apply(elements[count], arguments);
  }
  }
 }
 }
 });
 }
};

主要是用 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 的风格,优化代码:

(function () {
 var $ = function (element) {
 return new _$(element);
 };
 var _$ = function (element) {
 this.element = element && element.nodetype === 1 ? element : document;
 };
 _$.prototype = {
 constructor: _$,
 addevent: function (type, handler, usecapture) {
 var element = this.element;
 if (document.addeventlistener) {
 element.addeventlistener(type, handler, (usecapture ? usecapture : false));
 } else if (document.attachevent) {
 element.attachevent('on' + type, function () {
  handler.apply(element, arguments);
 });
 } else {
 element['on' + type] = function () {
  return handler.apply(element, arguments);
 };
 }
 return this;
 },
 getclasselements: function (classname) {
 var element = this.element, all, ele, classarr = [], classelements = [];
 if (element.getelementsbyclassname) {
 return element.getelementsbyclassname(classname);
 } else {
 all = element.getelementsbytagname('*');
 for (var i = 0, len = all.length; i < len; i++) {
  ele = all[i];
  classarr = ele && ele.classname && ele.classname.split(' ');
  if (classarr) {
  for (var j = 0; j < classarr.length; j++) {
  if (classarr[j] === classname) {
  classelements.push(ele);
  }
  }
  }
 }
 return classelements;
 }
 },
 delegate: function () { //参数:type, [selector,] handler
 var self = this,
 element = this.element,
 type = arguments[0],
 handler;
 if (arguments.length === 2) {
 handler = arguments[1];
 return self.addevent(type, handler);
 } else if (arguments.length === 3) {
 selector = arguments[1];
 handler = arguments[2];
 return self.addevent(type, function (event) {
  var event = event || window.event,
  target = event.target || event.srcelement,
  quickexpr = /^(?:[a-za-z]*#([\w-]+)|(\w+)|[a-za-z]*\.([\w-]+))$/,
  match,
  idelement,
  elements,
  tagname,
  count = 0,
  len;
  if (typeof selector === 'string') {
  match = quickexpr.exec(selector);
  if (match) {
  // #id selector
  if (match[1]) {
  idelement = document.getelementbyid(match[1]);
  tagname = match[0].slice(0, match[0].indexof('#'));
  // tag selector
  } else if (match[2]) {
  elements = element.getelementsbytagname(selector);
  // .class selector
  } else if (match[3]) {
  elements = self.getclasselements(match[3]);
  tagname = match[0].slice(0, match[0].indexof('.'));
  }
  }
  if (idelement) {
  if ( tagname ? tagname === idelement.nodename.tolowercase() && target === idelement ? target === idelement ) {
  return handler.apply(idelement, arguments);
  }
  } else if (elements) {
  for (len = elements.length; count < len; count++) {
  if ( tagname ? tagname === elements[count].nodename.tolowercase() && target === elements[count] : target === elements[count] ) {
   return handler.apply(elements[count], arguments);
  }
  }
  }
  }
 });
 }
 }
 };
 window.$ = $;
 return $;
}());

使用如下:

var outer = document.getelementbyid('outer');
$(outer).delegate('click', '.parag', function (event) {
 console.log(this.id);
});

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持!