放弃传统操作DOM的时代,基于vue/react开始数据影响视图模式

分离读写

渲染队列机制

    let box = document.getElementById('box');
    // 现代的浏览器都有渲染队列机制,所以下面的代码实际上只会进行一次的回流和渲染(老版本会引发三次渲染和回流)
    box.style.width='200px';
    box.style.height='200px';
    box.style.margin = '10px';

值得注意的是:

    <script>
        let box = document.getElementById('box');
        box.style.width='200px';
        // js盒子模型里面13个常用的属性会阻断渲染队列机制
        // 比如如果这样的话会结束一次渲染队列
        console.log(box.clientWidth);
        // 接着又会引发一次渲染和回流
        box.style.height='200px';
        box.style.margin = '10px';
    </script>

所以我们就可以引出分离读写的概念了,也就是说代码的读和写直接要分离开,代码应该写成如下:

    <script>
        let box = document.getElementById('box');
        box.style.width='200px';
        box.style.height='200px';
        box.style.margin = '10px';
        console.log(box.clientWidth);
    </script>

这样就是一次回流和渲染了
但是有些是后常常我们会忽略了这个问题,接着就引出了“批量处理”的概念

批量处理

批量处理其实很简单,就不不分开写相关的操作,比如修改样式的时候,我们把样式都写成一个类,然后直接操作类
比如有一个.last的类

        .last{
            width: 200px;
            height: 200px;
            margin: 10px;
            background: red;
            border: 10px solid green;
        }

我们直接通过下面的方法来操作

    <script>
        // 批量处理,这样也只引发一次回流和重绘
        let box = document.getElementById('box');
        box.className = 'last'
    </script>

缓存布局信息

比如有以下代码

    <script>
      let box = document.getElementById("box");
      box.style.width = box.clientWidth + 10 + "px";
      box.style.height = box.clientHeight + 10 + "px";
    </script>

粗一看,你可能以为这段代码和上文提到的分离读写类似,但是这里其实出现了两次回流和重绘,原因就是遇到了box.clientWidth这个“读”操作,然后浏览器渲染队列机制就会停止向下去寻找更改样式的代码放入队列,就会造成两次回流和渲染。而缓存布局信息就是为了解决这个问题

        <script>
            let box = document.getElementById("box");
            let bw = box.clientWidth
            let bh = box.clientHeight
            box.style.width = bw + 10 + "px";
            box.style.height = bh + 10 + "px";
        </script>

上面的代码本质来说还是将读写操作进行分离,先进行“读”操作,然后直接从缓存中拿到读取出来的信息,所以后面不再进行读操作,所以这里只进行了一次的回流和渲染

元素批量修改

文档碎片

        <script>
            let box = document.getElementById("box");
            // 1.文档碎片
            let frg = document.createDocumentFragment();
            for(let i = 0; i < 5; i++) {
                let newLi = document.createElement('li');
                newLi.innerHTML = i;
                // 创建的li放到文档碎片中
                frg.appendChild(newLi);
                frg = null
            }

模板字符串

        <script>
            let box = document.getElementById("box");
            let str = ``;
            for(let i=0; i<5; i++) {
                str+=`<li>${i}</li>`;
            }
            box.innerHTML = str
        </script>

动画效果运动到position属性为absolute或fixed的元素上(脱离文档流)

position属性为absolute或fixed会脱离文档流,也就是会生成一个新的层面。脱离文档流不意味着不会引起回流和重绘,肯定会引发回流和重绘,但是对其他元素不会产生影响(对其他层元素不会产生影响),也就是说动画效果运用到position属性为absolute或fixed会极大的提高性能。

CSS3硬件加速(GPU加速)

box.style.left = '100px'会引发回流
box.style.transform = 'translateX(200px)';不会引发回流
因为transform 开启的是浏览器或电脑的硬件加速,可以规避回流

比起考虑如何减少回流重绘,我们更期望的是,根本不要回流重绘;transform\opacity\filters...这些属性会触发硬件加速,不会引发回流和重绘...
但是可能引发的坑:过多使用会占用大量内存,性能消耗严重,有事会导致字体模糊等

牺牲平滑度换取速度

每次1像素移动一个动画,但是如果此动画使用了100%的cpu,动画就会看上去是跳动的,因为浏览器正则与更新回流做斗争。每次移动3像素可能看起来平滑度低了,但是它不会导致CPU在较慢的机器中抖动

避免table布局和使用css的JavaScript表达式