眾所周知, 瀏覽器中內存泄露以及內存無法回收(兩者不是一回事,很多人都把他們弄混淆了),常常是由于對dom元素注冊事件不當引起的.
通常的解決方案是, 自行實現一套 添加事件, 移除事件 以及刪除dom元素的機制.
為dom元素添加事件時, 同時記錄 這個事件 以及對應的函數,
在刪除dom元素時, 先移除dom元素上已經添加的事件 再刪除dom元素本身.
而當頁面中添加了事件監聽的dom元素很多時, 移除元素變得很麻煩.
例如 一個div 里面有個form form里有多個元素都添加了事件.
那么移除這個div時, 就要先去移除他下面每一個元素上的事件 然后再移除這個div.
這種做法很多時候是必須的, 而且自己寫一個"深度遍歷子節點,并移除其事件"的函數也并不是很困難.
但是 在很多時候 這種做法是可以避免的, 避免的方法就是, 把事件監聽注冊到更上層的dom元素中.
并且在事件函數中 通過 event.target/event.srcElement 來 事件發生在哪個元素上,然后來執行相關的方法.
這樣 在移除元素時 只要移除這個元素以及它上面的事件 就可以了, 而不必執行(或者少量的執行)"移除所有子節點事件"的動作了.
見下面的例子 :
在這個例子中, 實際上事件只是注冊在table上, 而沒有在"input type="button"上.
"showDetail" 可以這樣寫
當然 這種做法不是絕對的, 有時候這么做很可能讓代碼變得臃腫冗長.
到底是否使用"事件上提"的做法 要根據實際情況來選擇.
不過 根據我的以往經驗, 在列表(table)中, 使用這種技術非常合適.
因為 列表有著"行與行之間模型一致"(只是數據不一致,結構一致)的特點.
例如,下面的效果, 都可以通過在 table上注冊事件來實現:
1 點擊行, 行變色 (不必在 tr 上注冊點擊事件)
2 點擊行中的某個按鈕 (不必在 tr 里的 button 上注冊點擊事件)
3 鼠標經過行時 行變色 (不必在 tr上注冊 mouseover/mouseout 事件, 而是可以在table上注冊mousemove事件)
4 還有關于單元格的 很多效果.....
當然,在非列表里 這種做法也有很多的用武之地.
總之 合理的利用"事件上提"的方法, 可以增強dom元素和事件的可控性, 有效的防止內存泄露和內存無法回收的情況.
通常的解決方案是, 自行實現一套 添加事件, 移除事件 以及刪除dom元素的機制.
為dom元素添加事件時, 同時記錄 這個事件 以及對應的函數,
在刪除dom元素時, 先移除dom元素上已經添加的事件 再刪除dom元素本身.
而當頁面中添加了事件監聽的dom元素很多時, 移除元素變得很麻煩.
例如 一個div 里面有個form form里有多個元素都添加了事件.
那么移除這個div時, 就要先去移除他下面每一個元素上的事件 然后再移除這個div.
這種做法很多時候是必須的, 而且自己寫一個"深度遍歷子節點,并移除其事件"的函數也并不是很困難.
但是 在很多時候 這種做法是可以避免的, 避免的方法就是, 把事件監聽注冊到更上層的dom元素中.
并且在事件函數中 通過 event.target/event.srcElement 來 事件發生在哪個元素上,然后來執行相關的方法.
這樣 在移除元素時 只要移除這個元素以及它上面的事件 就可以了, 而不必執行(或者少量的執行)"移除所有子節點事件"的動作了.
見下面的例子 :
- <table width="300" border="1" onclick="showDetail(event)">
- <tr>
- <td>1</td>
- <td>Tom</td>
- <td><input type="button" value="詳細信息" userid="1" /></td>
- </tr>
- <tr>
- <td>2</td>
- <td>Kate</td>
- <td><input type="button" value="詳細信息" userid="2" /></td>
- </tr>
- <tr>
- <td>3</td>
- <td>John</td>
- <td><input type="button" value="詳細信息" userid="3" /></td>
- </tr>
- </table>
在這個例子中, 實際上事件只是注冊在table上, 而沒有在"input type="button"上.
"showDetail" 可以這樣寫
- function showDetail_b(event) {
- event=event||window.event;
- var target=event.target||event.srcElement;
- if ( String(target.tagName).toLowerCase()=='input' && target.value=="詳細信息") {
- showUserDetail(target.getAttribute('userid') );
- }
- }
當然 這種做法不是絕對的, 有時候這么做很可能讓代碼變得臃腫冗長.
到底是否使用"事件上提"的做法 要根據實際情況來選擇.
不過 根據我的以往經驗, 在列表(table)中, 使用這種技術非常合適.
因為 列表有著"行與行之間模型一致"(只是數據不一致,結構一致)的特點.
例如,下面的效果, 都可以通過在 table上注冊事件來實現:
1 點擊行, 行變色 (不必在 tr 上注冊點擊事件)
2 點擊行中的某個按鈕 (不必在 tr 里的 button 上注冊點擊事件)
3 鼠標經過行時 行變色 (不必在 tr上注冊 mouseover/mouseout 事件, 而是可以在table上注冊mousemove事件)
4 還有關于單元格的 很多效果.....
當然,在非列表里 這種做法也有很多的用武之地.
總之 合理的利用"事件上提"的方法, 可以增強dom元素和事件的可控性, 有效的防止內存泄露和內存無法回收的情況.