事件委托(事件代理)

链接地址:http://www.cnblogs.com/liugang-vip/p/5616484.html
http://www.webhek.com/post/event-delegate.html
在知道什么是事件委托之前,我们应该知道什么叫事件对象?
事件(Event)对象就是在对事件进行点击啊,鼠标按下啊,右键啊等事件的状态。
事件对象w3school网址:http://www.w3school.com.cn/jsref/dom_obj_event.asp
那什么叫事件委托呢?它还有一个名字叫事件代理,JavaScript高级程序设计上讲:事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。
有三个同事预计会在周一收到快递。为签收快递,有两种办法:一是三个人在公司门口等快递;二是委托给前台MM代为签收。现实当中,我们大都采用委托的方案(公司也不会容忍那么多员工站在门口就为了等快递)。前台MM收到快递后,她会判断收件人是谁,然后按照收件人的要求签收,甚至代为付款。这种方案还有一个优势,那就是即使公司里来了新员工(不管多少),前台MM也会在收到寄给新员工的快递后核实并代为签收。
这里其实还有2层意思的:
第一,现在委托前台的同事是可以代为签收的,即程序中的现有的dom节点是有事件的;
第二,新员工也是可以被前台MM代为签收的,即程序中新添加的dom节点也是有事件的。
总之:事件委托就是将一类类似的事情都交给一个人去操作,而不用每个dom节点排队等候。
为什么要用事件委托:
在JavaScript中,添加到页面上的事件处理程序数量将直接关系到页面的整体运行性能,因为需要不断的与dom节点进行交互,访问dom的次数越多,引起浏览器重绘与重排的次数也就越多,就会延长整个页面的交互就绪时间,这就是为什么性能优化的主要思想之一就是减少DOM操作的原因;如果要用事件委托,就会将所有的操作放到js程序里面,与dom的操作就只需要交互一次,这样就能大大的减少与dom的交互次数,提高性能。总之:减少DOM节点的操作,优化性能。

事件委托原理:
利用事件冒泡机制来实现的。何为事件冒泡呢?就是事件从最深的节点开始,然后逐步向上传播事件,举个例子:页面上有这么一个节点树,div>ul>li>a;比如给最里面的a加一个click点击事件,那么这个事件就会一层一层的往外执行,执行顺序a>li>ul>div,有这样一个机制,那么我们给最外面的div加点击事件,那么里面的ul,li,a做点击事件的时候,都会冒泡到最外层的div上,所以都会触发,这就是事件委托,委托它们父级代为执行事件。我们只用给父元素添加监听器,而不用再一步步的去遍历子元素,在子元素上添加事件监听器,增加开销。
事件委托的实现:
//常规做法,不用事件委托


  • 111

  • 222

  • 333

  • 444



js代码:

window.onload = function(){
var oUl = document.getElementById("ul1");
var aLi = oUl.getElementsByTagName('li');
for(var i=0;i aLi[i].onclick = function(){
alert(123);
}
}
}

常规做法:先应该获取到父元素ul,然后遍历子元素li,点击li,找到li的位置,再执行相同的操作。开销大,增加了DOM的操作
事件委托怎么做的呢?

window.onload = function(){
var oUl = document.getElementById("ul1");
oUl.onclick = function(){
alert(123);//这里只要是ul下的子元素都会冒泡到ul上
}
}

这里用父级ul做事件处理,当li被点击时,由于冒泡原理,事件就会冒泡到ul上,因为ul上有点击事件,所以事件就会触发,当然,这里当点击ul的时候,也是会触发的.所以我们应该消除这个bug。解决:用Event对象来获取目标源,然后再进行操作。
Event对象提供了一个属性叫target,可以返回事件的目标节点,我们成为事件源,也就是说,target就可以表示为当前的事件操作的dom,但是不是真正操作dom,当然,这个是有兼容性的,标准浏览器用ev.target,IE浏览器用event.srcElement,此时只是获取了当前节点的位置,并不知道是什么节点名称,这里我们用nodeName来获取具体是什么标签名,target.nodeName(或者用target.tagName)返回的都是一个大写的,我们需要转成小写再做比较(习惯问题):
//用jquery写法
直接注册点击函数,用的是onclick注册(这里只对冒泡可行,捕获不行)

$(function(){
var ul = document.getElementById('ul1');
ul.onclick = function(ev){
var ev = ev || window.event;
var target = ev.target || ev.srcElement;
if(target.nodeName.toLowerCase() == 'li'){
alert("1231");
cosole.log(target.nodeName)//LI
}
}})

//js原生写法
//W3C推荐的事件绑定用的是addEventListener()函数,同时支持冒泡和捕获
//这种写法支持的浏览器有IE9以上以及谷歌之类的,IE9下的IE浏览器只能用attachEvent()函数执行。

window.onload = function(){
var ul = document.getElementById('ul2');
ul.addEventListener('click',function(ev){
var ev = ev || window.event;
var target = ev.target || ev.srcElement;
if(target.nodeName.toLowerCase() == 'li'){
console.log(target.tagName);//LI
alert("1232");
}
},false);//false表示冒泡阶段调用,true表示捕获阶段调用事件的处理程序

上面的例子给出的都是对不同的li进行相同的操作,适用于表格的删除和新增一行等重复性的机械工作。
下面将对相似的li(不同的id)进行不同的操作(常规做法是获取每一个的id再进行click事件绑定,执行操作,简单不细说)。现在我介绍的是怎样用事件委托来进行不同的id注册事件进行操作。



  • 1

  • 2

  • 3

  • 4




//jquey代码

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.toLocaleLowerCase() == 'li'){
switch(target.id){
case 'add' :
alert('添加');
break;
case 'remove' :
alert('删除');
break;
case 'move' :
alert('移动');
break;
case 'select' :
alert('选择');
break;
}
}
}
}

//js原生实现,用的是addEventListener()添加监听器

window.onload = function(){
var oul = document.getElementById('ul3');
oul.addEventListener('click',function(ev){
var ev = ev || window.event;
var target = ev.target || ev.srcElement;
if(target.nodeName.toLowerCase() == 'li'){
switch(target.id){
case 'add':
alert('新增!');
break;
case 'remove':
alert('删除!');
break;
case 'move' :
alert('移动');
break;
case 'select' :
alert('选择');
break;
}
}
},false);
}

上面的使用事件委托的形式,只进行操作了一次DOM节点的操作。到达事件捕获的终点,就算是一次节点操作。
这里我们要注意的是event.target和event.currentTarget首先本质区别是:

event.target返回触发事件的元素(目标源,实际点击的元素)

event.currentTarget返回绑定事件的元素(绑定的元素即监听器元素,一般为父元素)
上面讲的都是在页面加载完成之后我们的dom节点的操作,现在讨论下我们用事件委托的形式为新添加的元素绑定事件进行操作。(下次继续写)

你可能感兴趣的:(事件委托(事件代理))