zoukankan      html  css  js  c++  java
  • 【JavaScript】回流(reflow)与重绘(repaint)

    重绘与回流

    首先要了解页面是如何呈现的

    1. HTML文档加载后生成DOM树(包括display:none;元素);
    2. 在DOM树的基础上配合css样式结构体生成render树(不包含display:none;、head节点,包含visibility:hidden;节点),即页面中的占位确定了.
    3. 最后绘制页面(也叫渲染),不会改变页面布局的一些属性:color、背景色等。
    • 重绘(repaint):更新页面元素的属性引起的,如颜色、透明度等不会改变页面布局而需要重新渲染的。
    • 回流(reflow):render树中部分或全部元素的尺寸、布局、隐藏等(内容、结构、位置)改变引起的,每个页面至少有一次回流(即初始构建页面时),成本较高。
    • DOM操作(对元素的增删改、顺序变化等)
    • 内容变化,包括表单区域内的文本变化
    • css属性的更改或者重新计算
    • 增删样式表内容
    • 修改class属性
    • 浏览器窗口变化(滚动或缩放)
    • 伪类样式激活(:hover等)

    这些情况会引起回流,减少回流就是尽量避免或减少这写操作的执行次数。

    减少页面重绘与回流:
    页面中需要需要动态生成id为box的div中的内容,结果如下:

    <div id="box">
        <p class="btn-title"><i class="iconfont"></i>项目阶段</p>
        <ul class="btn-group" id="proStepul">
            <li class="btn-item" data_id="">全部</li>
            <li class="btn-item" data_id="">全部</li>
            <li class="btn-item" data_id="">全部</li>
            <li class="btn-item" data_id="">全部</li>
            <li class="btn-item" data_id="">全部</li>
        </ul>
    </div>

    一般的做法可以用innerHTML或者createElement:

    var Obox = document.getElementById("box");
    Obox.innerHTML = '<p class="btn-title"><i class="iconfont"></i>项目阶段</p>';
    Obox.innerHTML += '<ul class="btn-group" id="proStepul">';
    for(var i=0;i<5;i++){
        Obox.innerHTML += '<li class="btn-item" data_id="">全部</li>';
    }
    Obox.innerHTML +='</ul>';

    这样写要向Obox中写入很多次。成本增高,建议的方法是用变量存储然后一次写入。

    var Obox = document.getElementById("box");
    var str = '';
    str = '<p class="btn-title"><i class="iconfont"></i>项目阶段</p>';
    str += '<ul class="btn-group" id="proStepul">';
    for(var i=0;i<5;i++){
        str += '<li class="btn-item" data_id="">全部</li>';
    }
    str +='</ul>';
    Obox.innerHTML = str;

    用createElement方法如下:可是这样的结构很糟糕,多次写入,增加很多重绘与回流。

        var Obox = document.getElementById("box");
        var Op = document.createElement("p");
        Obox.appendChild(Op);
        Op.setAttribute("class","btn-title");
        Op.innerHTML ="项目阶段";
        var Oi = document.createElement("i");
        Op.appendChild(Oi);
        Oi.setAttribute("class","iconfont");
    
        var Oul = document.createElement("ul");
        Obox.appendChild(Oul);
        Oul.setAttribute("class","btn-group");
        Oul.setAttribute("id","proStepul");
        for(var i=0;i<5;i++){
            var Oli = document.createElement("li");
            Oul.appendChild(Oli);
            Oli.setAttribute("class","btn-item");
        }

    合理的方法是:先构建元素,然后设置元素的属性等,最后再将元素添加到页面相应位置:

        var Obox = document.getElementById("box");
        var Op = document.createElement("p");
        //Obox.appendChild(Op);
        Op.setAttribute("class","btn-title");
        Op.innerHTML ="项目阶段";
        var Oi = document.createElement("i");
        Op.appendChild(Oi);
        Oi.setAttribute("class","iconfont");
    
        var Oul = document.createElement("ul");
        //Obox.appendChild(Oul);
        Oul.setAttribute("class","btn-group");
        Oul.setAttribute("id","proStepul");
        for(var i=0;i<5;i++){
            var Oli = document.createElement("li");
            Oul.appendChild(Oli);
            Oli.setAttribute("class","btn-item");
        }
    
        Obox.appendChild(Op);
        Obox.appendChild(Oul);

    这里只需将新建元素写入页面的操作移到最后即可,至于元素在未写入页面之前的操作顺序如何,对页面并没有什么影响,不会造成页面回流或者重绘。
    有一种情况为:需要像页面中写入多个同一级的元素,如下:向ul元素中写入多个li元素

    <ul class="btn-group on" id="proStepul">
        <li class="btn-item on" >全部</li>
        <li class="btn-item on" >全部</li>
        <li class="btn-item on" >全部</li>
        <li class="btn-item on" >全部</li>
        <li class="btn-item on" >全部</li>
    </ul>

    如果用之前的方法,不可避免的要写五个Oul.appendChild("Oul");了,这时我们可以用JS提供的可以整合多个碎片的中介----document.createDocumentFragment();

        var Oul = document.getElementById("proStepul");
        var obj = document.createDocumentFragment();
        for (var i = 0; i < 5; i++) {
            var Oli = document.createElement("li");
            Oli.setAttribute("class", "btn-item");
            obj.appendChild(Oli);
        }
        Oul.appendChild(obj);
  • 相关阅读:
    WordPress“无法将上传的文件移动至wp-content/uploads/”的解决办法
    npm安装less和less-loadernpm或者stylus和stylus-loader
    vue-cli脚手架安装
    JavaScript 中的回调函数
    css同时满足两个类名才有效果的写法
    jQuery对象与JS原生对象之间的转换
    css3在动画完成后执行事件
    5秒让你的View变3D,ThreeDLayout使用和实现
    给大家安利一个学习angular2的视频网站
    JAVA中的常量定义在class中还是interface中比较合理?
  • 原文地址:https://www.cnblogs.com/fanshaokun/p/8117700.html
Copyright © 2011-2022 走看看