首页 > 代码库 > JS(原生)事件委托:为动态创建的节点绑定事件

JS(原生)事件委托:为动态创建的节点绑定事件

项目开发中经常需要为动态创建的节点绑定事件,

比如需要创建一个动态列表:在li的数量非常少的时候,为每一个li绑定事件不会存在太多性能方面的问题,但是当列表非常的长,长到上百上千甚至上万的时候(假设),为每个li绑定事件就会对页面性能产生很大的影响。当有大量元素需要绑定相同事件的时候可采用事件委托,将在目标元素上要处理的事件委托给父元素或者祖先元素

    优点
    事件委托对于web应用程序的性能有如下几个优点:
    1.需要管理的函数变少了
    2.占用的内存少了
    3.javascript代码和Dom结构之间的关联更少了

首先动态创建节点:

点击按钮 创建一个li节点并将文本框中输入的值做为此节点的内容,新创建的LI节点插入到最前面

HTML代码:

 1 <body>
 2 <input id="txt1" type="text"/>
 3 <input id="btn1" type="button" value="创建li"/>
 4 <ul id="ul1">
 5 </ul>
 6 
 7 <script>
 8 window.onload = function(){
 9     var oul  = document.getElementById("ul1");
10     var obtn = document.getElementById("btn1");
11     var otxt = document.getElementById("txt1");
12 
13     /************************添加节点**********************************/
14     obtn.onclick = function(){
15         var oli = document.createElement(li);
16         oli.innerHTML = otxt.value +  &nbsp;&nbsp;<a class="ac" href="javascript:;">删除</a>;
17         ali = oul.getElementsByTagName("li");
18         
19         //1:追加元素
20         //oul.appendChild(oli);
21         
22         //2:插入元素到前面
23         //oul.insertBefore(oli,ali[0]); 若不存在元素ali[0]在IE中会报错 所以需要兼容
24         if( ali.length > 0 )
25         {
26             oul.insertBefore(oli, ali[0]);
27         }
28         else
29         {
30             oul.appendChild(oli);
31         }            
32     }
33     
34 }
35 
36 </script>
View Code

 

其次为LI中的A元素绑定点击事件:点击A元素删除所在的LI节点

采用事件委托,有如下两种方法供大家参考:

方法一:传统绑定 [直接给元素绑定事件]

 1 <body>
 2 <input id="txt1" type="text"/>
 3 <input id="btn1" type="button" value="创建li"/>
 4 <ul id="ul1">
 5 </ul>
 6 
 7 <script>
 8 window.onload = function(){
 9     var oul  = document.getElementById("ul1");
10     var obtn = document.getElementById("btn1");
11     var otxt = document.getElementById("txt1");
12 
13     /************************添加节点**********************************/
14     obtn.onclick = function(){
15         var oli = document.createElement(li);
16         oli.innerHTML = otxt.value +  &nbsp;&nbsp;<a class="ac" href="javascript:;">删除</a>;
17         ali = oul.getElementsByTagName("li");
18         
19         if( ali.length > 0 )
20         {
21             oul.insertBefore(oli, ali[0]);
22         }
23         else
24         {
25             oul.appendChild(oli);
26         }            
27     }
28     
29     /************************绑定事件**********************************/
30     oul.onclick = function( e ) {
31         e = e || window.event;
32         var t = e.target || e.srcElement;  //t:目标对象
33         var tagName = t.tagName; //tagName标签名称
34         if( tagName == A ) {
35              this.removeChild(t.parentNode); //删除元素 this指oul
36         }
37     }
38     
39 }
40 
41 </script>
View Code

方法1: a、优点:

    1、简单可靠,确保在不同的浏览器中保持一致;

    2、处理事件时,this关键字引用的是当前的元素;

   b、缺点:

    1、只支持冒泡阶段的运行;

    2、一个元素一次只能绑定一个事件处理函数,同类事件处理函数会相互覆盖;[如给同一元素绑定两次.onclick事件,则只有最后一个绑定成功]

 

方式二:事件监听

在IE6-8下可用attachEvent,在IE9,谷歌和火狐下则要用addEventListener
若为同一元素多次绑定,则会产生追加的效果,事件触发是的执行顺序,由下至上

    attachEvent()有两个参数
    第一个是事件名称
    第二个是需执行的函数;

    addEventListener()有三个参数
    第一个是事件名称,但与IE事件不同的是,事件不带"on",比如"onsubmit"在这里应为"submit"
    第二个是需执行的函数
    第三个参数为布尔值,表示该事件的响应顺序(useCapture),userCapture若为true,则浏览器采用Capture[捕获], 若为false则采用bubbing[冒泡]方式。

对函数进行封装后兼容各大主流浏览器的监听事件如下:

 1 /*
 2  *  oTarget:监听对象 
 3  *  sEventType:监听事件类型,如click,mouseover 
 4  *  fnHandler:监听函数 
 5  */  
 6 function addEventHandler(oTarget, sEventType, fnHandler) {    
 7     if (oTarget.addEventListener) {   //监听IE9,谷歌和火狐  
 8         oTarget.addEventListener(sEventType, fnHandler, false);    
 9     } else if (oTarget.attachEvent) {  //IE  
10         oTarget.attachEvent("on" + sEventType, fnHandler);    
11     } else {    
12         oTarget["on" + sEventType] = fnHandler;    
13     }    
14 }  

HTML代码:

 1 <body>
 2 <input id="txt1" type="text"/>
 3 <input id="btn1" type="button" value="创建li"/>
 4 <ul id="ul1">
 5 </ul>
 6 
 7 <script>
 8 
 9 window.onload = function(){
10     var oul  = document.getElementById("ul1");
11     var obtn = document.getElementById("btn1");
12     var otxt = document.getElementById("txt1");
13 
14     /************************添加节点**********************************/
15     obtn.onclick = function(){
16         var oli = document.createElement(li);
17         oli.innerHTML = otxt.value +  &nbsp;&nbsp;<a class="ac" href="javascript:;">删除</a>;
18         ali = oul.getElementsByTagName("li");
19 
20         if( ali.length > 0 )
21         {
22             oul.insertBefore(oli, ali[0]);
23         }
24         else
25         {
26             oul.appendChild(oli);
27         }    
28         
29     }
30 
31   /************************绑定事件**********************************/
32     function fnHandle(e)
33     {
34         e = e || window.event;  //IE window.event
35         var t = e.target || e.srcElement; //目标对象
36         var classname = t.className;
37         if( classname == ac )
38         {
39             oul.removeChild(t.parentNode);
40         }        
41     }    
42     
43     addEventHandler(oul, click, fnHandle);
44 
45 }
46 
47 /*
48  *  oTarget:监听对象 
49  *  sEventType:监听事件类型,如click,mouseover 
50  *  fnHandler:监听函数 
51  */  
52 function addEventHandler(oTarget, sEventType, fnHandler) {    
53     if (oTarget.addEventListener) {   //监听IE9,谷歌和火狐  
54         oTarget.addEventListener(sEventType, fnHandler, false);    
55     } else if (oTarget.attachEvent) {  //IE  
56         oTarget.attachEvent("on" + sEventType, fnHandler);    
57     } else {    
58         oTarget["on" + sEventType] = fnHandler;    
59     }    
60 }   
61     
62 </script>
View Code

 

既然讲到了采用事件监听给对象绑定方法,那也顺便说说解除相应的绑定

在IE6-8下可用detachEvent,在IE9,谷歌和火狐下则要用removeEventListener

对函数进行封装后兼容各大主流浏览器的解除事件监听方法如下:

 1 /* 
 2  * 采用事件监听给对象绑定方法后,可以解除相应的绑定 
 3  *  oTarget:监听对象 
 4  *  sEventType:监听事件类型,如click,mouseover 
 5  *  fnHandler:监听函数 
 6  */  
 7 function removeEventHandler(oTarget, sEventType, fnHandler) {  
 8     if (oTarget.removeEventListener){  
 9         //监听IE9,谷歌和火狐  
10         oTarget.removeEventListener(sEventType, fnHandler, false);  
11     } else if (oTarget.detachEvent){  
12         oTarget.detachEvent("on" + sEventType, fnHandler);  
13     }else {  
14         delete oTarget["on" + sEventType];  
15     }  
16 }

HTML代码:

 1 <input id="txt1" type="text"/>
 2 <input id="btn1" type="button" value="创建li"/>
 3 <ul id="ul1">
 4 </ul>
 5 
 6 <script>
 7 
 8 window.onload = function(){
 9     var oul  = document.getElementById("ul1");
10     var obtn = document.getElementById("btn1");
11     var otxt = document.getElementById("txt1");
12 
13     /************************添加节点**********************************/
14     obtn.onclick = function(){
15         var oli = document.createElement(li);
16         oli.innerHTML = otxt.value +  &nbsp;&nbsp;<a class="ac" href="javascript:;">删除</a>;
17         ali = oul.getElementsByTagName("li");
18 
19         if( ali.length > 0 )
20         {
21             oul.insertBefore(oli, ali[0]);
22         }
23         else
24         {
25             oul.appendChild(oli);
26         }    
27         
28     }
29 
30   /************************绑定事件**********************************/
31     function fnHandle(e)
32     {
33         e = e || window.event;  //IE window.event
34         var t = e.target || e.srcElement; //目标对象
35         var classname = t.className;
36         if( classname == ac )
37         {
38             oul.removeChild(t.parentNode);
39         }        
40     }    
41     
42     //事件绑定
43     addEventHandler(oul, click, fnHandle);
44     //解除绑定
45     removeEventHandler(oul,click,fnHandle);
46 
47 }
48 
49 /*
50  *  oTarget:监听对象 
51  *  sEventType:监听事件类型,如click,mouseover 
52  *  fnHandler:监听函数 
53  */  
54 function addEventHandler(oTarget, sEventType, fnHandler) {    
55     if (oTarget.addEventListener) {   //监听IE9,谷歌和火狐  
56         oTarget.addEventListener(sEventType, fnHandler, false);    
57     } else if (oTarget.attachEvent) {  //IE  
58         oTarget.attachEvent("on" + sEventType, fnHandler);    
59     } else {    
60         oTarget["on" + sEventType] = fnHandler;    
61     }    
62 }   
63 
64 /* 
65  * 采用事件监听给对象绑定方法后,可以解除相应的绑定 
66  *  oTarget:监听对象 
67  *  sEventType:监听事件类型,如click,mouseover 
68  *  fnHandler:监听函数 
69  */  
70 function removeEventHandler(oTarget, sEventType, fnHandler) {  
71     if (oTarget.removeEventListener){  
72         //监听IE9,谷歌和火狐  
73         oTarget.removeEventListener(sEventType, fnHandler, false);  
74     } else if (oTarget.detachEvent){  
75         oTarget.detachEvent("on" + sEventType, fnHandler);  
76     }else {  
77         delete oTarget["on" + sEventType];  
78     }  
79 } 
80     
81 </script>
View Code

注:解除绑定事件的时候一定要用函数的句柄,把整个函数写上是无法解除绑定的

 1     //正确写法    
 2     removeEventHandler(oul,‘click‘,fnHandle);
 3     
 4     //错误写法    
 5     removeEventHandler(oul,‘click‘,function(e)
 6     {
 7         e = e || window.event;  //IE window.event
 8         var t = e.target || e.srcElement; //目标对象
 9         var classname = t.className;
10         if( classname == ‘ac‘ )
11         {
12             oul.removeChild(t.parentNode);
13         }        
14     });

方法一解除绑定:oul.onclick = null;

 

总结:

方法一和方法二的区别
当同一个对象使用.onclick的写法触发多个方法的时候,后一个方法会把前一个方法覆盖掉,也就是说,在对象的onclick事件发生时,只会执行最后绑定的方法。

而用事件监听则不会有覆盖的现象,每个绑定的事件都会被执行,也便于解除事件绑定