什么是事件委托呢?
字面意思,通俗地来讲,就是把一个元素响应事件(click、keydown......)的函数委托到另一个元素;
因为其的事件冒泡性质机制,会把一个或者一组元素的事件委托到它的父层或者更外层元素上,真正绑定事件的是外层元素,当事件响应到需要绑定的元素上时,会通过事件冒泡机制从而触发它的外层元素的绑定事件上,然后在外层元素上去执行函数。
事件委托的优点:
1. 提高性能:每一个函数都会占用内存空间,只需添加一个事件处理程序代理所有事件,所占用的内存空间更少。
2. 动态监听:使用事件委托可以自动绑定动态添加的元素,即新增的节点不需要主动添加也可以一样具有和其他元素一样的事件。
假设这样一个列表结构
<ul id="list">
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
</ul>
我们把li元素的事件委托到他的父级身上
// 给父层元素绑定事件
document.getElementById('list').addEventListener('click', function (e) {
// 兼容性处理
var event = e || window.event;
var target = event.target || event.srcElement;
// 判断是否匹配目标元素
if (target.nodeName.toLocaleLowerCase === 'li') {
console.log('the content is: ', target.innerHTML);
}
});
在上述代码中, target 元素则是在 #list 元素之下具体被点击的元素,然后通过判断 target 的一些属性(比如:nodeName,id 等等)可以更精确地匹配到某一类 #list li 元素之上;
事件委托的封装:
// 模仿 : jQuery 工具库实现委托的方法;
// on( 元素 object , 事件类型 string , 事件处理函数 function )
function on( ele , type , cb_selector , cb){
// 做一个基本判断 :
// 1. 正常绑定事件;
// 2. 实现事件委托; 多一个参数 => 选择器;
// 严谨 : 1. 参数数量不一样 ;
// 2. cb_selector => 正常 是函数;
// => 委托 是字符串;
if(arguments.length === 4 && typeof cb_selector === "string"){
// 事件委托;
// 如果你的程序只有两套逻辑,在第一个逻辑之中直接return false ;
// 可以省略第二个if逻辑;
ele.addEventListener( type , function(evt){
// 在里面加上逻辑进行判断;
// 根据逻辑决定是否调用 事件处理函数;
var e = evt || event;
var target = e.target || e.srcElement;
// 判定 :
var node = target;
// 判定究竟是什么选择器非常重要;
// 截取选择器的开头;
var selector_start = cb_selector.substr(0,1);
var selector_type = null;
// 为了不让cb_selector 重复截取,那么在这进行一个替换;
var selector = cb_selector;
switch( selector_start ){
case "." :
selector_type = "className";
// 去掉选择符;
selector = cb_selector.slice(1);
break;
case "#" : selector_type = "id";
// 去掉选择符;
selector = cb_selector.slice(1);
break;
default :
selector_type = "nodeName";
break;
}
while( node !== ele ){
// 你为啥知道这个是类名那 ?
// 选择器定了;
// 如果此时判定的是标签,那么这个时候我们需要将传入的参数大写;
// 上述代码逻辑 : (selector_type === "nodeName" ? selector.toUpperCase() : selector)
if(node[selector_type] === (selector_type === "nodeName" ? selector.toUpperCase() : selector)){
cb();
break;
}
node = node.parentNode;
}
});
return false;
}
ele.addEventListener( type , cb_selector);
}
var btn_ele = document.getElementById("btn");
// 正常事件绑定的参数传递方法;
// on( btn_ele , "click" , function(){
// alert("hello world")
// });
// 事件委托的参数传递方法;
// 翻译一下 : body下面带有 class名为 btn的元素发生点击事件了,会执行这个事件处理函数;
on( document.body , "click" , "#btn" , function(){
alert("hello world")
})