文章目錄
DOM 的各種事件為豐富的互動提供了可能,在現在的 web 應用程式中,事件處理常式越來越多,越來越複雜,頁面中隨處可見的事件監聽已經司空見慣,但這引出了一個效能的問題,事件監聽得越多,頁面運行效能就越差。主要原因來自兩個方面:1. 每添加一個事件監聽,載入頁面時都會增加一次對被監聽節點的訪問,這無疑增加了頁面完全準備就緒所需的時間;2. 每一個事件監聽函數都會佔用記憶體,而 JavaScript 並不具備分配記憶體的權利,有限的記憶體如果被事件監聽函數佔用得越多,頁面效能下降得也越多。
假如有下面的一個無序列表,需要在每一個 li 被點擊之後添加或移除一個名為 'active' 的 class 用以標記該項為紅色或還原。
<ul id="list"><li>list 1</li><li>list 2</li><li>list 3</li><li>list 4</li><li>list 5</li></ul>
傳統監聽方法:
$('#list li').click(function(){$(this).toggleClass('active');});
在上面的代碼中通過 jQuery 的選取器,找到了這個無序列表中的每一個 li 元素,並為其綁定了 click 事件,代碼看上去很簡單,但實際上 $('#list li') 返回了一個數組,在這個數組中包含了 5 個上面的 li 元素,然後通過迭代為這 5 個元素分別綁定了一個事件處理函數,這意味著當這段 JavaScript 代碼被執行過後,記憶體中多了 5 個對象。
使用事件委託:
事件委託的原理是事件冒泡,這個過程大致如所示:
圖中右邊部分 (Bubbling Phase) 即為事件冒泡的過程,當元素的一個事件被觸發後,這個事件會像冒泡一樣一直向上(父元素)傳遞,直到 document ( Firefox ,Chrome ,Safari 冒泡到 window),事件委託的核心就是監聽一個 DOM 中更高層、更不具體的元素,等到事件冒泡到這個不具體元素時,通過 event 對象的 target 屬性來擷取觸發事件的具體元素。下面的代碼使用了事件委託的方法改進了這個事件處理函數。
$('#nav').click(function(event){var target = event.target;$(target).toggleClass('active');});
在這裡,被監聽的元素變成了 ul,即剛才所說的不具體的元素。由於事件的冒泡,在每一個 li 上的 click,都會觸發 ul 的事件監聽,然後通過 event 中的 target 這個指向事件目標(具體元素)的屬性擷取到被點擊到的那個 li ,最後切換 class 'active' 的有無,任務完成。
通過使用事件委託這個技巧,達到相同的目標只監聽了一個元素的事件,同樣也只添加了 1 個事件處理函數。瀏覽器為添加事件所要尋找並引用的 DOM 更少,由於監聽函數變少,記憶體的使用也同時減少了。如果頁面上需要添加事件的元素很多,事件委託對於頁面效能改善的作用是不可小視的。