js事件代理(委托)
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);
});
js事件代理(委托)的更多相关文章
- JS 事件代理
事件处理器:onclick.onmouseover.... 在传统的事件处理中,你需要为每一个元素添加或者是删除事件处理器.然而,事件处理器将有可能导致内存泄露或者是性能下降——你用得越多这种风险就越 ...
- JavaScript中的事件代理/委托
事件委托在JS高级程序设计中的定义为"利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件" 如何理解上面的这句话呢,在网上,大牛们一般都使用收快递这个例子来解释的, ...
- js事件代理
需要注意的blog:http://blog.csdn.net/majian_1987/article/details/8591385 一篇博客看懂 http://blog.csdn.net/maji ...
- 封装Js事件代理方法
// 封装事件代理 function delegateEvent(element, tag, event, listener) { // 判断是否支持addEventlistener if(eleme ...
- 关于JS事件冒泡与JS事件代理(事件委托)
连接:https://blog.csdn.net/supercoooooder/article/details/52190100 核心代码: <ul id="parentUl" ...
- js中事件代理(委托)
var oul = document.getElementById(‘uli’); oul.onclick = function(e) { e = e || window.event; var tar ...
- JS事件流(W3C与IE区别)
一.JS事件的3个阶段:捕获.目标.冒泡,低版本IE不支持捕获阶段: 二.在浏览器解析事件的时候,有两种触发方式:一种叫做Bubbling(冒泡),另外一种叫做Capturing(捕获). 冒泡的方式 ...
- js中的事件委托或是事件代理详解
起因: 1.这是前端面试的经典题型,要去找工作的小伙伴看看还是有帮助的: 2.其实我一直都没弄明白,写这个一是为了备忘,二是给其他的知其然不知其所以然的小伙伴们以参考: 概述: 那什么叫事件委托呢?它 ...
- JS中事件代理与委托
在javasript中delegate这个词经常出现,看字面的意思,代理.委托.那么它究竟在什么样的情况下使用?它的原理又是什么?在各种框架中,也经常能看到delegate相关的接口.这些接口又有什么 ...
随机推荐
- 单节点下多个Tomcat服务器并存的端口号配置
一个服务器节点同时安装多个tomcat服务器时,如果仅仅修改访问端口号则会提示端口冲突启动失败,还需要修改另外端口号解决,一共需要修改3处地方,修改如下: 编辑配置文件:server.xml 1.首先 ...
- C++虚函数浅探
C++中和虚函数(Virtual Function)密切相关的概念是"动态绑定"(Dynamic Binding),与之相对的概念是"静态绑定"(Static ...
- 模仿mybatis,用jdk proxy实现接口
在mybatis中,我们都只需要定义一个mapper接口,但并不需要对它进行任务实现.只要有对就的mapper.xml文件就可以访问数据库.那么,没有接口的访问是如何实现的呢. 答案就是JDK pro ...
- LeetCode 88 Merge Sorted Array
Problem: Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array ...
- oracle 11g RAC安装节点二执行结果错误CRS-5005: IP Address: 192.168.1.24 is already in use in the network
[root@testdb11b ~]# /u01/app/oraInventory/orainstRoot.sh Changing permissions of /u01/app/oraInvento ...
- oracle 12c中的隐含列
Invisible Columns 使用select * from ,desc 等看不到该列, DROP TABLE tab1 PURGE; CREATE TABLE tab1 ( id NUMB ...
- Mybatis实现数据的增删改查(CRUD)
什么是 MyBatis? MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架. MyBatis 消除了几乎所有的 JDBC 代码和参数的手工设置以及对结果集的检索.MyBat ...
- Semaphore
信号量玩的也是aqs的state. package com.hust.grid.leesf.semaphore; import java.util.concurrent.Semaphore; clas ...
- 使用代理和block写一个alertView
代理: MyAlertView.h: @property (nonatomic,assign)id delegate; @protocol MyAlertViewDelegate <NSObje ...
- 通用数据库操作类,前端easyui-datagrid,form
实现功能: 左端datagrid显示简略信息,右侧显示选中行详细信息,数据库增删改 (1)点击选中行,右侧显示详细信息,其中[新增].[修改].[删除]按钮可用,[保存]按钮禁用 (2)点击[ ...