[关闭]
@greenfavo 2015-12-14T14:37:36.000000Z 字数 2253 阅读 702

js事件代理

博客


假设html中有个列表ul,我们想每点击一个li时都输出它的索引号,一般我们想到的方法是为每个li绑定click事件。当li比较少时,这是可以,但是当li很多,有上百个时,如果还是为每个li绑定事件,那性能就比较差了,而且还很容易出现很多问题。这时候应该用事件代理或者叫做事件委托。

不用代理的写法

  1. <div id='out'>
  2. <ul id='middle'>
  3. <li>1</li>
  4. <li>2</li>
  5. <li>3</li>
  6. <li>4</li>
  7. <li>5</li>
  8. </ul>
  9. </div>
  10. <script>
  11. function clickLi(){
  12. var oLi=document.getElementsByTagName('li');
  13. for(var i=0;i<oLi.length;i++){
  14. oLi[i].onclick=function(){
  15. console.log(i);
  16. }
  17. }
  18. }
  19. clickLi();
  20. </script>

上面代码并不会输出对应的i值,而一直输出5。因为执行click事件时for循环已经结束了。但是用事件代理就不会出现这种问题。

什么是事件代理

简单地说就是当你想为一个元素添加事件时,可以把事件绑定到它父级元素上,利用事件传播机制,可以把从子元素获得的事件传播到父元素上。这样就可以避免把事件处理程序添加到多个子元素上。从而提高性能。针对上面的例子,看一下事件代理的实现方法。

  1. var out = document.getElementById('out');
  2. var middle = document.getElementById('middle');
  3. oUl=addEventListener('click',function(event){
  4. event=event.target||window.event;
  5. var target=event.target;
  6. if(target.tagName.toLowerCase()=='li'){//target返回的标记都是大写的
  7. console.log(target.innerHTML);
  8. console.log(this);//this是oUl
  9. }
  10. })

事件传播机制

事件传播是浏览器决定哪个对象触发其事件处理程序的过程。有2种传播机制,冒泡和捕获。

事件冒泡是指当一个元素上发生事件时,事件会沿着DOM树一层层地向上传播,一直冒泡到DOM树的最上层,所以它的父元素也得到了这个事件。

事件捕获指当某个元素触发某个事件(如onclick),顶层对象document就会向下发出一个事件流,随着DOM树的节点向目标元素节点流去,直到到达事件真正发生的目标元素。在这个过程中,事件相应的监听函数是不会被触发的。

js事件处理的过程是先从上往下捕获,找到目标元素,然后从下往上冒泡找到绑定的事件对象执行事件处理程序。

所以在上面的例子中,我们把click事件绑定到li的父级元素ul上,当点击相应的li时(此时li是目标元素),点击事件会从最下面的li向上冒泡到ul上,此时ul添加的事件监听程序就触发执行了。事件处理程序默认采取冒泡机制传播事件。不过可以给addEventListener加第3个参数来让它在捕获阶段就触发事件处理程序。

  1. oUl.addEventListener('click',function(){},true);//true表示在捕获阶段执行事件程序,false表示在冒泡阶段执行事件处理程序,默认false

看看第三个参数设为true和false的区别:

  1. out.addEventListener('click', function(event){//最外层的元素
  2. console.log(event.target);
  3. console.log(this);//后输出
  4. },false);
  5. middle.addEventListener('click', function (){//中间的元素
  6. console.log('我先输出');//先输出这个
  7. },true);

虽然为out绑定的事件写在上面,但下面的事件处理先执行,这就是因为浏览器是先捕获后冒泡,当addEventListner的第三个参数useCapturing设为true时代表在捕获阶段就执行事件处理程序了。

事件代理的好处

1,很明显需要创建的以及驻留在内存中的事件处理程序少了,提高了性能。
2,在DOM树更新后无需重新绑定事件。如果页面是动态生成的,比如说通过Ajax,你不需要再重新绑定事件。一般来说,事件处理程序只能添加在添加事件处理程序时已经存在的元素,对通过ajax后来追加的元素不起作用。解决的方法一是重新绑定事件,二是早早地把事件绑定到父级元素上。

注意

不是所有的事件都能冒泡的。blur、focus、load和unload不能像其它事件一样冒泡。

停止冒泡

  1. function myParagraphEventHandler(e) {
  2. e = e || window.event;
  3. // 停止向上冒泡
  4. if (e.stopPropagation) {
  5. // W3C实现
  6. e.stopPropagation();
  7. } else {
  8. // IE实现
  9. e.cancelBubble = true;
  10. }
  11. }
  12. // 使用我们自定义的addEvent函数将myParagraphEventHandler绑定到click事件上:
  13. addEvent(document.getElementsByTagName('p')[0], 'click', myParagraphEventHandler);
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注