前端机能优化(DOM操纵篇)

正巧看到在送书,于是乎找了找自身博客上记录过的一些东西来及其无耻的蹭书了~~~

小广告:更多内容能够看我的博客

缓存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";

经由过程事宜代办批量操纵事宜

照样之前谁人ul和增加li,假如我们须要给每一个li都绑定一个click事宜,就可能写出相似以下代码:

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);

这里每一个li元素都须要实行一次addEventListener()要领,假如li元素数目一多,就会下降效力。所以我们能够经由过程事宜代办的体式格局,将事宜绑定在ul上,然后经由过程event.target来肯定被点击的元素是不是是li元素,同时我们也能够运用innerHTML属性一次性建立节点了,修正代码为:

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);

如许事宜绑定的代码就只需实行一次,能够监听一切li元素的事宜了。固然假如须要移除事宜回调函数,我们也不须要轮回遍历一切的li元素,只须要移除ul元素上的事宜处置惩罚就好了

    原文作者:天镶
    原文地址: https://segmentfault.com/a/1190000000490322
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞