項目開發中經常需要為動態創建的節點綁定事件,
比如需要創建一個動態列表:在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 + ' <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>
其次為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 + ' <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>
方法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 + ' <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>
既然講到了采用事件監聽給對象綁定方法,那也順便說說解除相應的綁定
在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 + ' <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>
注:解除綁定事件的時候一定要用函數的句柄,把整個函數寫上是無法解除綁定的
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事件發生時,只會執行最后綁定的方法。
而用事件監聽則不會有覆蓋的現象,每個綁定的事件都會被執行,也便於解除事件綁定
