如何减少Dom操作中的回流和重绘问题

作者: 痛心凉 | 来源:发表于2017-10-09 20:49 被阅读58次

    什么是回流和重绘?

    (1)当render tree中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。这就称为回流(reflow)。然而,每一个页面至少需要回流一次,就是在页面第一次加载的时候。在回流的时候,浏览器会使渲染树中受影响的一部分失效,并重新构造这部分渲染树,完成回流后,浏览器会重新绘制受影响的部分到屏幕中,该过程为重绘。
    (2)当render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,比如background-color,这就是重绘。

    *注意:回流必然会引起重绘,而重绘不一定会引起回流。

    常见的重绘和回流操作?

    (1)添加、删除元素(回流+重绘)
    (2)隐藏元素,display:none(回流+重绘)
    (3)移除元素,比如改变top,left(jQuery的animate方法就是,该变top,left不一定会回流),或者移动元素到另外1个父元素中。(回流+重绘)
    (4)对style的操作(对不同的属性操作,影响不一样)
    (5)以下属性,只要改动他们的值,就会造成回流,这些属性包括:offsetLeft、offsetTop、offsetWidth、offsetHeight;scrollTop、scrollLeft、scrollWidth、scrollHeight;clientWidth、clientHeight、clientLeft、clientTop;
    (6)还有一种是用户的操作,比如改变浏览器大小,改变浏览器的字体大小。

    如何减少回流和重绘

    减少回流、重绘其实就是需要减少对 render tree的操作(合并多次Dom和样式的修改),并减少对一下style信息的请求,尽量利用好浏览器的优化策略。具体方法如下:

    1.直接改变className,如果动态改变样式,则使用cssText(考虑没有优化的浏览器)

    // 不好的写法
    var left = 1;
    var top = 1;
    el.style.left = left + "px";
    el.style.top = top + "px";
    // 比较好的写法
    el.className += " className1";
    // 比较好的写法
    el.style.cssText += ";
    left: " + left + "px;
    top: " + top + "px;";

    2. 让要操作的元素进行”离线处理”,处理完后一起更新

    a) 使用DocumentFragment进行缓存操作,引发一次回流和重绘;

    //不好的写法(模式中所说的反模式)
    var p, t;
    p = document.creatElement('p');
    t = document.creatTextNode('fist paragraph');
    p.appendChild(t);document.body.appendChild(p); //将引起一次回流
    p = document.creatElement('p');
    t = document.creatTextNode('second paragraph');
    p.appendChild(t);document.body.appendChild(p); //将再引起一次回流
    //好的写法
    var p, t, frag;
    frag = document.creatDocumentFragment();
    p = document.creatElement('p');
    t = document.creatTextNode('fist paragraph');
    p.appendChild(t);
    farg.appendChild(p);
    p = document.creatElement('p');
    t = document.creatTextNode('second paragraph');
    p.appendChild(t);
    farg.appendChild(p);
    document.body.appendChild(frag); //相比前面的方法,这里仅仅引起一次回流,倘若页面里有很多这样的操作,利用文档随便将会提升很多
    b) 使用display:none技术,只引发两次回流和重绘; ( 只是减少重绘和回流的次数,display:none 是会引起重绘并回流,相对来说,visibility: hidden只会引起重绘 )
    c) 使用cloneNode(true or false) 和 replaceChild 技术,引发一次回流和重绘;
    //建立克隆镜像var oldNode = document.getElementById('target'), clone = oldNode.cloneNode(true); //深复制// 处理克隆对象的操作....//完成后oldNode.parentNode.replaceChild(clone,oldNode);

    3.不要经常访问会引起浏览器flush队列的属性,如果你确实要访问,利用缓存

    //BAD WAYfor(循环)
    {el.style.left = el.offsetLeft + 5 + "px";el.style.top = el.offsetTop + 5 + "px";} // 这样写好点
    var left = el.offsetLeft,top = el.offsetTop,s = el.style;
    for (循环) { left += 10; top += 10; s.left = left + "px"; s.top = top + "px"; }

    4. 让元素脱离动画流,减少回流的Render Tree的规模**

    相关文章

      网友评论

        本文标题:如何减少Dom操作中的回流和重绘问题

        本文链接:https://www.haomeiwen.com/subject/djnpyxtx.html