1、定义
事件委托就是利用事件冒泡机制,只指定一个事件处理程序,就可以管理某一类的所有事件
2、为什么要用事件委托?
给DOM添加事件处理程序后,需要不断的与DOM节点进行交互,访问DOM的次数越多,引起浏览器重排和重绘的次数也越多。如果用事件委托,就可以将所有的操作放入到js程序里面,与DOM的操作就只需要交互一次,这样可以大大的减少与DOM的交互次数,提高性能
3、DOM2级事件
- 事件捕获:当某个元素触发某个事件(如onclick),顶层对象document就会发出一个事件流,随着DOM树的节点向目标元素节点流去,直到到达事件真正发生的目标元素。在这个过程中,事件相应的监听函数是不会被触发的
- 事件目标:当到达目标元素之后,执行目标元素该事件相应的处理函数。如果没有绑定监听函数,那就不执行
- 事件冒泡:从目标元素开始,往顶层元素传播。途中如果有节点绑定了相应的事件处理函数,这些函数都会被一次触发。如果想阻止事件起泡,可以使用e.stopPropagation()(Firefox)或者e.cancelBubble=true(IE)来阻止事件的冒泡传播
4、如何实现事件委托?
(1)当li操作是同样的效果
<ul id="ul1">
<li>111</li>
<li>222</li>
<li>333</li>
<li>444</li>
</ul>
无事件委托:
window.onload = function(){
var oUl = document.getElementById("ul1");
var aLi = oUl.getElementsByTagName('li');
for(var i=0;i<aLi.length;i++){
aLi[i].onclick = function(){
alert(123);
}
}
}
有事件委托:
window.onload = function(){
var oUl = document.getElementById("ul1");
oUl.onclick = function(){
alert(123);
}
}
用父级ul做事件代理,当li被点击时,由于冒泡原理,事件就会被冒泡到ul上,因为ul上有点击事件,所以事件就会被触发。注意,此时点击ul,也是会触发的。如何实现只有点击li才会触发?
Event对象提供了一个属性叫target,可以返回事件的目标节点,我们称为事件源。
window.onload = function(){
var oUl = document.getElementById("ul1");
oUl.onclick = function(ev){
var ev = ev || window.event;
var target = ev.target || ev.srcElement;
if(target.nodeName.toLowerCase() == 'li'){
alert(123);
alert(target.innerHTML);
}
}
}
(2)当li操作效果不同
<div id="box">
<input type="button" id="add" value="添加" />
<input type="button" id="remove" value="删除" />
<input type="button" id="move" value="移动" />
<input type="button" id="select" value="选择" />
</div>
window.onload = function(){
var oBox = document.getElementById("box");
oBox.onclick = function (ev) {
var ev = ev || window.event;
var target = ev.target || ev.srcElement;
if(target.nodeName.toLowerCase() == 'input'){
switch(target.id){
case 'add' :
alert('添加');
break;
case 'remove' :
alert('删除');
break;
case 'move' :
alert('移动');
break;
case 'select' :
alert('选择');
break;
}
}
}
}
(3)如果是新增的节点,会有事件吗?
给每个li节点绑定事件,当没有使用事件委托机制时,新增的li是没有事件的。
无事件委托:
<input type="button" name="" id="btn" value="添加" />
<ul id="ul1">
<li>111</li>
<li>222</li>
<li>333</li>
<li>444</li>
</ul>
window.onload = function(){
var oBtn = document.getElementById("btn");
var oUl = document.getElementById("ul1");
var aLi = oUl.getElementsByTagName('li');
var num = 4;
//鼠标移入变红,移出变白
for(var i=0; i<aLi.length;i++){
aLi[i].onmouseover = function(){
this.style.background = 'red';
};
aLi[i].onmouseout = function(){
this.style.background = '#fff';
}
}
//添加新节点
oBtn.onclick = function(){
num++;
var oLi = document.createElement('li');
oLi.innerHTML = 111*num;
oUl.appendChild(oLi);
};
}
有事件委托:
window.onload = function(){
var oBtn = document.getElementById("btn");
var oUl = document.getElementById("ul1");
var aLi = oUl.getElementsByTagName('li');
var num = 4;
//事件委托,添加的子元素也有事件
oUl.onmouseover = function(ev){
var ev = ev || window.event;
var target = ev.target || ev.srcElement;
if(target.nodeName.toLowerCase() == 'li'){
target.style.background = "red";
}
};
oUl.onmouseout = function(ev){
var ev = ev || window.event;
var target = ev.target || ev.srcElement;
if(target.nodeName.toLowerCase() == 'li'){
target.style.background = "#fff";
}
};
//添加新节点
oBtn.onclick = function(){
num++;
var oLi = document.createElement('li');
oLi.innerHTML = 111*num;
oUl.appendChild(oLi);
};
}
当用事件委托的时候,根本不需要去遍历元素的子节点,新增的子元素也带有事件效果。
注:在事件处理程序内部,对象this始终等于currentTarget的值,而target则只包含事件的实际目标
document.body.onclick = function(event) {
alert(event.currentTarget === document.body); // true
alert(event.this === document.body); // true
alert(event.target === document.getElementById("myBtn")) //true
}
this和currentTarget都等于document.body,因为事件是注册到这个元素上的,但是target元素等于按钮元素,因为它是click事件真正的目标。