优化DOM的本质其实就是减少DOM树的重流与重绘。
优化DOM的结构,无非就是引用保存,动画优化,节点保存,更新节点等基本操作。
获取到DOM节点后一定要记得保存。否则,下场很难看的。
为什么
我们都知道所谓的js其实是DOM,BOM,ECMA结合的产物。 本来我js挺快的,你非要去的DOM说说话。 那怎么办,只有敲敲门,等DOM来回应你呀~ 但是,这个等待时间灰常长。
看个demo吧.

vartimes=10000;vartime1=function(){vartime=times;while(time--){//DOM的两个操作放在循环内vardom=document.querySelector("#Div1");dom.innerHTML+="a";}};vartime2=function(){vartime=times,dom=document.querySelector("#Div1");while(time--){//DOM的一个操作放在循环内dom.innerHTML+="a";}};vartime3=function(){vartime=times,dom=document.querySelector("#Div1"),str="";while(time--){//循环内不放置DOM的操作str+="a";}dom.innerHTML=str;}console.time(1);//设置时间起点time1();console.timeEnd(1);console.time(2);//设置时间起点time2();console.timeEnd(2);console.time(3);//设置时间起点time3();console.timeEnd(3);//测试结果为:1:101.868ms2:101.560ms3:13.615ms

当然,这只是个比较夸张的例子了,当你过多的频繁操作DOM的时候,一定要记得保存。 而且,保存一定是要保存所有涉及DOM相关的操作。
比如. style,innerHTML等属性。
而这样做的原理就是减少重流和重绘的次数。

重流重绘发生的情况

那重流和重绘通常什么情况下会发生呢?
重流发生情况:

添加或者删除可见的DOM元素

元素位置改变

元素尺寸改变

元素内容改变(例如:一个文本被另一个不同尺寸的图片替代)

页面渲染初始化(这个无法避免)

浏览器窗口尺寸改变

总的来说,就是改变页面的布局,大小,都会发生重流的情况。
那重绘什么时候会发生呢? 发生重流就一定会发生重绘,但是,重绘的范围比重流稍微大了一点。比如,当你仅仅改变字体颜色,页面背景颜色等 比较"肤浅"的操作时,是不会打扰到重排的。

合并DOM的操作

当我们这样操作时:

div.style.color="red";div.style.border="1pxsolidred";

浏览器会很聪明的将两次重排合并到一次发生,节省资源。 其实函数节流的思想和这个有异曲同工的妙处

varthrottle=(function(){vartime;returnfunction(fn,context){clearTimeout(time);//进行函数的节流time=setTimeout(fn.bind(context),200);}})()

这个技巧通常用在你调整浏览器大小的时候。
但是,如果中间,你访问了offsetTop,clientTop等 立即执行属性的话。那结果你就么么哒了。

div.style.color="red";//积累一次重排记录varheight=div.clientHeight;//触发重排div.style.border="1pxsolidred";//再次积累一次重排

这时候,浏览器已经被你玩傻了。 所以,给的一点建议就是,如果要更改DOM结构最好一次性整完,或者,要整一起整~
我们上面的css修改,还可以这样

div.style.cssText="color:red;border:1pxsolidred";//覆盖原来的cssdiv.classList.add("change");//利用class来整体改动DOM操作的优化

DOM的操作无非就CRUD。
这里简单说一下基本的API

创建节点

vardiv=document.createELement("div");查找节点

vardivs=document.querySelectorAll('div');//很多个,放在数组内varonlydiv=document.querySelector('div');//只有一个//以及document.getElement系列查看节点

varhtml=div.innerHTML;varouter=div.outerHTML;//这两个是非常常用的varclassNames=div.classList;varclassName=div.className;vartagName=div.tagName;varid=div.id;varstyle=div.getAttribute("style");//....移动节点

ele.replaceChild(replace,replaced);//replace代替replaced//添加子节点ele.appendChild(child);//删除子节点ele.removeChild(child);//插入子节点ele.insertBefore(newEle,referenceEle);

Ok~ 其实,上面所说的这些API只要涉及到DOM操作的都会发生重排。所以,这里是地方可以优化的.

使用fragment

当我们需要批量加入子节点的时候,就需要使用fragment这个虚拟片断,来作为一个容器.
比如,我们需要在div里面添加100个p标签

vartimes=100;varaddP=function(){vartime=times,tag1=document.querySelector('#tag1');while(time--){varp=document.createElement('p');tag1.appendChild(p);}}varuseFrag=function(){vartime=times,tag1=document.querySelector('#tag1'),frag=document.createDocumentFragment();while(time--){varp=document.createElement('p');frag.appendChild(p);}tag1.appendChild(frag);}console.time(1);addP();console.timeEnd(1);console.time(2);useFrag();console.timeEnd(2);//基本事件差为:1:1.352ms2:0.685ms

除了使用fragment片断,还可以使用innerHTML,outerHTML进行相关的优化操作。

UI操作的优化

这里想说的其实不多,就是学会使用absolute排版。 因为当你进行相关UI操作的时候,毫无疑问有可能不经意间,导致全屏的渲染。
他这里不一样,他直接使用absolute进行布局,脱离了文档流,防止页面过度的重排,赞~