事件代理又称事件委托,事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。
1.1那为什么要使用事件委托呢?
在JavaScript中,添加到页面上的事件处理程序数量直接关系到页面的整体的运行性能,因为需要不断的与dom节点进行交互,访问dom的次数越多,引起浏览器重绘与重拍的次数也就越多,会延长整个页面的交互就绪时间,这就是为什么性能优化的主要思想之一就是减少dom操作的原因。如果用事件委托,就会将所有的操作放到js程序中,与dom的操作就只需要交互一次,大大减少了与dom的交互次数,提高性能。
1.2事件委托的原理:
事件委托就是利用事件冒泡的原理来实现的。(以下是分不同情况举的例子)
1.2.1对document加载完成的现有dom节点进行操作
"ul1">
- li1
- l12
- li3
- li4
/*这是一般情况下,我们为li添加事件的方式;首先要找到ul,然后遍历li,然后点击li的时候,又要找一次目标的li的位置,才能执行最后的操作,每次点击都要找一次li*/
window.onload = function(){
var oUl = document.getElementById("ul1");
var aLi = oUl.getElementsByTagName('li');
for(var i=0;ifunction(){
alert("li");
}
}
}
/*这是使用事件委托的方式;这里用父级ul做事件处理,当ul(或li)被点击的时候,就会触发ul的事件处理程序*/
window.onload=function(){
var oUl=document.getElementById("ul1");
oUl.onclick=function(){
alert("li");
}
}
那么,如果想实现事件代理的效果跟直接给节点的事件效果一样(只有点击li才会触发)怎么办呢?
Event对象提供了一个属性叫target,可以返回事件的目标节点,意思是,target就可以表示为当前的事件操作的dom,but不是真正操作dom,标准浏览器用ev.target,IE浏览器用event.srcElement,(ev.target||event.srcElement)这只是获取了当前节点的位置,并不知道节点名称,使用nodeName来获取具体的标签名,这返回的是一个大写的,我们最好转成小写在做比较:
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("li");
alert(target.innerHTML);
}
}
}
这样改下就只有点击li会触发事件了,且每次只执行一次dom操作,如果li数量很多的话,将大大减少dom的操作,优化的性能可想而知!上述例子中 所有的li的效果相同。接下来用事件代理实现不同效果的例子:
"ul2">
- "li1">li1
- "li2">l12
- "li3">li3
- "li4">li4
window.onload = function(){
var oBox = document.getElementById("ul2");
ul2.onclick = function (ev) {
var ev = ev || window.event;
var target = ev.target || ev.srcElement;
if(target.nodeName.toLocaleLowerCase() == 'li'){
switch(target.id){
case 'li1' :
target.style.background = 'blue';
break;
case 'li2' :
target.style.background = 'green';
break;
case 'li3' :
target.style.background = 'pink';
break;
case 'li4' :
target.style.background = 'yellow';
break;
}
}
}
}
1.2.2对新增的dom节点进行操作,使其有对应的事件处理程序
"button" name="" id="btn" value="添加" />
"ul1">
- 111
- 222
- 333
- 444
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);
};
}
我们可以发现,当用事件委托的时候,根本就不需要去遍历元素的子节点,只需要给父级元素添加事件就好了,其他的都是在js里面的执行,这样可以大大的减少dom操作,这才是事件委托的精髓所在。
总结:
那什么样的事件可以用事件委托,什么样的事件不可以用呢?
适合用事件委托的事件:click,mousedown,mouseup,keydown,keyup,keypress。
值得注意的是,mouseover和mouseout虽然也有事件冒泡,但是处理它们的时候需要特别的注意,因为需要经常计算它们的位置,处理起来不太容易。
不适合的就有很多了,举个例子,mousemove,每次都要计算它的位置,非常不好把控,在不如说focus,blur之类的,本身就没用冒泡的特性,自然就不能用事件委托了。
var arr1=new Array(1,2,3,4,5,6,7);
function arrreverse(arr){
var i=0;j=arr.length-1;len=arr.length;
for(i;i2;i++){
var temp=arr[i];
arr[i]=arr[j-i];
arr[j-i]=temp;
}
console.log(arr);
}
arrreverse(arr1);
创建:
createDocumentFragment();//创建一个DOM片段
createElement();//创建以一个具体的元素
createTextNode();//创建一个文本节点
添加:
appendChild();//用于添加新元素到尾部
insertBefore();//用于新元素添加到开始位置
移除已存在的元素:removeChild();//需要知道该元素的父元素。
替换:replaceChild(old, new);
复制:cloneNode(true)
查找:
getElementsByTagName() //通过标签名称
getElementsByClassName() //通过标签名称
getElementsByName() //通过元素的Name属性的值
getElementById() //通过元素Id,唯一性
本人在写这篇博客时候,也是借鉴了许多其他优秀的文章,非常感谢各位大神的分享。以上内容如有不正确的地方,还希望大家积极指正。谢谢啦
**本文章还会继续更新哦**