緩存DOM對象
JavaScript的DOM操作可以說是JavaScript最重要的功能,我們經常要根據使用者的操作來動态的增加和删除元素,或是通過AJAX傳回的資料動态生成元素。比如我們獲得了一個很多元素的數組data[],需要将其每個值生成一個li元素插入到一個id為container的ul元素中,最簡單(最慢)的方式是:
var liNode, i, m;
for (i = 0, m = data.length; i < m; i++) {
liNode = document.createElement("li");
liNode.innerText = data[i];
document.getElementById("container").appendChild(liNode);
}
這裡每一次循環都會去查找id為container的元素,效率自然非常低,是以我們需要将元素在循環前查詢完畢,在循環中僅僅是引用就行了,修改代碼為:
var ulNode = document.getElementById("container");
var liNode, i, m;
for (i = 0, m = data.length; i < m; i++) {
liNode = document.createElement("li");
liNode.innerText = data[i];
ulNode.appendChild(liNode);
}
緩存DOM對象的方式也經常被用在元素的查找中,查找元素應該是DOM操作中最頻繁的操作了,其效率優化也是大頭。在一般情況下,我們會根據需要,将一些頻繁被查找的元素緩存起來,在查找它或查找它的子孫元素時,以它為起點進行查找,就能提高查找效率了。
在記憶體中操作元素
由于DOM操作會導緻浏覽器的回流,回流需要花費大量的時間進行樣式計算和節點重繪與渲染,是以應當盡量減少回流次數。一種可靠的方法就是加入元素時不要修改頁面上已經存在的元素,而是在記憶體中的節點進行大量的操作,最後再一并将修改運用到頁面上。DOM操作本身提供一個建立記憶體節點片段的功能:document.createDocumentFragment(),我們可以将其運用于上述代碼中:
var ulNode = document.getElementById("container");
var liNode, i, m;
var fragment = document.createDocumentFragment();
for (i = 0, m = data.length; i < m; i++) {
liNode = document.createElement("li");
liNode.innerText = data[i];
fragment.appendChild(liNode);
}
ulNode.appendChild(fragment);
這樣就隻會觸發一次回流,效率會得到很大的提升。如果需要對一個元素進行複雜的操作(删減、添加子節點),那麼我們應當先将元素從頁面中移除,然後再對其進行操作,或者将其複制一個(cloneNode()),在記憶體中進行操作後再替換原來的節點
一次性DOM節點生成
在這裡我們每次都需要生成節點(document.createElement("li")),然後将其加入到記憶體片段中,我們可以通過innerHTML屬性來一次性生成節點,具體的思路就是使用字元串拼接的方式,先生成相應的HTML字元串,最後一次性寫入到ul的innerHTML中。修改代碼為:
var ulNode = document.getElementById("container");
var fragmentHtml = "", i, m;
for (i = 0, m = data.length; i < m; i++) {
fragmentHtml += "<li>" + data[i] + "</li>";
}
ulNode.innerHTML = fragmentHtml;
這樣效率也會有提升,不過手動拼寫字元串是相當麻煩的一件事
通過類修改樣式
有時候我們需要通過JavaScript給元素增加樣式,比如如下代碼:
element.style.fontWeight = 'bold';
element.style.backgroundImage = 'url(back.gif)';
element.style.backgroundColor = 'white';
element.style.color = 'white';
//...
這樣效率很低,每次修改style屬性後都會觸發元素的重繪,如果修改了的屬性涉及大小和位置,将會導緻回流。是以我們應當盡量避免多次為一個元素設定style屬性,應當通過給其添加新的CSS類,來修改其CSS
.element {
background-image: url(back.gif);
background-color: #fff;
color: #fff;
font-weight: 'bold';
/*...*/
}
element.className += " element";
通過事件代理批量操作事件
var ulNode = document.getElementById("container");
var fragment = document.createDocumentFragment();
var liNode, i, m;
var liFnCb = function(evt){
//do something
};
for (i = 0, m = data.length; i < m; i++) {
liNode = document.createElement("li");
liNode.innerText = data[i];
liNode.addEventListener("click", liFnCb, false);
fragment.appendChild(liNode);
}
ulNode.appendChild(fragment);
var ulNode = document.getElementById("container");
var fragmentHtml = "", i, m;
var liFnCb = function(evt){
//do something
};
for (i = 0, m = data.length; i < m; i++) {
fragmentHtml += "<li>" + data[i] + "</li>";
}
ulNode.innerHTML = fragmentHtml;
ulNode.addEventListener("click", function(evt){
if(evt.target.tagName.toLowerCase() === 'li') {
liFnCb.call(evt.target, evt);
}
}, false);
部落格中所涉及到的圖檔都有版權,請謹慎使用