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事件發生時,只會執行最后綁定的方法。

而用事件監聽則不會有覆蓋的現象,每個綁定的事件都會被執行,也便於解除事件綁定
  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM