淺談JavaScript的事件(事件委托)
事件處理程序為Web程序提供了系統交互,但是如果頁面中的事件處理程序太多,則會影響頁面的性能。每個函數都是對象,都會占用內存,內存中對象越多,性能越差。需要事先為DOM對象指定事件處理程序,導致訪問DOM的次數增多,會延遲整個頁面的交互就緒時間。
- 事件委托
對事件處理程序過多的解決方案是使用事件委托。事件委托利用了事件冒泡,只指定一個事件處理程序,就可以管理某一類型的所有事件。比如click事件會一直冒泡到document,也就是說我們只需為整個頁面指定一個onclick事件處理程序,而不必為每個需要點擊事件的元素單獨添加。
1 <ul id="ul1"> 2 <li id="li1">111</li> 3 <li id="li2">222</li> 4 </ul>
例如上面的代碼,如果我們采用常規手段來添加事件處理程序,我們需要為每個li都添加事件。但是如果采用冒泡,我們只需要指定一個事件處理程序,並且能夠實現同樣的功能。
1 var oUl = document.getElementById("ul1"); 2 EventUtil.addEvent(oUl, "click", function(ev) { 3 var ev = EventUtil.getEvent(ev);4 var target = EventUtil.getTarget(ev); 5 if(target.id == ‘li1‘) { 6 console.log("1"); 7 } 8 else if(target.id=="li2"){ 9 console.log("2"); 10 } 11 });
上面的代碼中,通過事件冒泡為ul1指定了事件處理程序,在我們單擊li的時候通過事件冒泡也會觸發該事件,並且能夠通過target來獲取當前單擊的元素對象。通過元素id,為每個元素執行不同的if語句。
並不是所有的事件都適合使用事件委托,比較適用的事件是:mouseup、mousedown、click、keyup、keydown和keypress。雖然mouseover和mouseout也支持事件冒泡,但是如果使用事件委托則處理就比較麻煩,而且需要計算鼠標的位置以及元素的位置(當鼠標從一個元素移到其子節點,或者移出元素都會觸發mouseout事件)。
1 var oUl = document.getElementById("ul1"); 2 EventUtil.addEvent(oUl, "mouseout", function(ev) { 3 var ev = EventUtil.getEvent(ev); 4 var target = EventUtil.getTarget(ev); 5 if(target.id == ‘li1‘) { 6 console.log("1"); 7 } 8 else if(target.id=="li2"){ 9 console.log("2"); 10 } 11 });
比如上面的代碼,當鼠標移到li元素的時候會觸發mouseout,鼠標移出ul元素的時候也會觸發mouseout事件。
- 移除事件處理程序
前文已經講過事件的添加以及事件的移除。對於頁面的事件處理程序太多,會影響頁面的性能,除了使用事件委托之外,還可以將一些事件移除。內存中留有的一些過時的用不到的事件處理程序也是造成Web頁面和內存性能的主要問題。
我們移除頁面中的元素時候,可以通過removeChild和replaceChild方法,但有時候也會使用innerHTML來替換元素。如果某個元素有事件處理程序,通過innerHTML來替換,則事件處理程序依然存在,那麽該事件處理程序已經使用不到,但是它也無法被回收,會一直占用內存空間。
1 <div id="firstdiv"> 2 <input type="button" id="btnadd" value="添加" /> 3 </div>
1 EventUtil.addEvent(document.getElementById("btnadd"),"click",function(event){ 2 document.getElementById("firstdiv").innerHTML="processing"; 3 });
上面的代碼中為btnadd元素綁定了單擊事件,單擊的時候通過innerHTML移除了該元素,但是元素的事件處理程序並沒有移除,依然留在內存中。
1 var callback =function(event){ 2 EventUtil.removeEvent(document.getElementById("btnadd"),"click",callback); 3 document.getElementById("firstdiv").innerHTML="processing"; 4 } 5 EventUtil.addEvent(document.getElementById("btnadd"),"click",callback);
上面的代碼,我們在元素移除之前,手動移除了元素的事件處理程序。這樣確保內存中也移除了該事件處理程序,而從DOM中移除按鈕也非常徹底。
淺談JavaScript的事件(事件委托)