@greenfavo
2015-12-14T06:37:36.000000Z
字数 2253
阅读 789
博客
假设html中有个列表ul,我们想每点击一个li时都输出它的索引号,一般我们想到的方法是为每个li绑定click事件。当li比较少时,这是可以,但是当li很多,有上百个时,如果还是为每个li绑定事件,那性能就比较差了,而且还很容易出现很多问题。这时候应该用事件代理或者叫做事件委托。
<div id='out'><ul id='middle'><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li></ul></div><script>function clickLi(){var oLi=document.getElementsByTagName('li');for(var i=0;i<oLi.length;i++){oLi[i].onclick=function(){console.log(i);}}}clickLi();</script>
上面代码并不会输出对应的i值,而一直输出5。因为执行click事件时for循环已经结束了。但是用事件代理就不会出现这种问题。
简单地说就是当你想为一个元素添加事件时,可以把事件绑定到它父级元素上,利用事件传播机制,可以把从子元素获得的事件传播到父元素上。这样就可以避免把事件处理程序添加到多个子元素上。从而提高性能。针对上面的例子,看一下事件代理的实现方法。
var out = document.getElementById('out');var middle = document.getElementById('middle');oUl=addEventListener('click',function(event){event=event.target||window.event;var target=event.target;if(target.tagName.toLowerCase()=='li'){//target返回的标记都是大写的console.log(target.innerHTML);console.log(this);//this是oUl}})
事件传播是浏览器决定哪个对象触发其事件处理程序的过程。有2种传播机制,冒泡和捕获。
事件冒泡是指当一个元素上发生事件时,事件会沿着DOM树一层层地向上传播,一直冒泡到DOM树的最上层,所以它的父元素也得到了这个事件。
事件捕获指当某个元素触发某个事件(如onclick),顶层对象document就会向下发出一个事件流,随着DOM树的节点向目标元素节点流去,直到到达事件真正发生的目标元素。在这个过程中,事件相应的监听函数是不会被触发的。
js事件处理的过程是先从上往下捕获,找到目标元素,然后从下往上冒泡找到绑定的事件对象执行事件处理程序。
所以在上面的例子中,我们把click事件绑定到li的父级元素ul上,当点击相应的li时(此时li是目标元素),点击事件会从最下面的li向上冒泡到ul上,此时ul添加的事件监听程序就触发执行了。事件处理程序默认采取冒泡机制传播事件。不过可以给addEventListener加第3个参数来让它在捕获阶段就触发事件处理程序。
oUl.addEventListener('click',function(){},true);//true表示在捕获阶段执行事件程序,false表示在冒泡阶段执行事件处理程序,默认false
看看第三个参数设为true和false的区别:
out.addEventListener('click', function(event){//最外层的元素console.log(event.target);console.log(this);//后输出},false);middle.addEventListener('click', function (){//中间的元素console.log('我先输出');//先输出这个},true);
虽然为out绑定的事件写在上面,但下面的事件处理先执行,这就是因为浏览器是先捕获后冒泡,当addEventListner的第三个参数useCapturing设为true时代表在捕获阶段就执行事件处理程序了。
1,很明显需要创建的以及驻留在内存中的事件处理程序少了,提高了性能。
2,在DOM树更新后无需重新绑定事件。如果页面是动态生成的,比如说通过Ajax,你不需要再重新绑定事件。一般来说,事件处理程序只能添加在添加事件处理程序时已经存在的元素,对通过ajax后来追加的元素不起作用。解决的方法一是重新绑定事件,二是早早地把事件绑定到父级元素上。
不是所有的事件都能冒泡的。blur、focus、load和unload不能像其它事件一样冒泡。
function myParagraphEventHandler(e) {e = e || window.event;// 停止向上冒泡if (e.stopPropagation) {// W3C实现e.stopPropagation();} else {// IE实现e.cancelBubble = true;}}// 使用我们自定义的addEvent函数将myParagraphEventHandler绑定到click事件上:addEvent(document.getElementsByTagName('p')[0], 'click', myParagraphEventHandler);