• 重排和重绘


    重排和重绘

    每个页面至少在初始化的时候会有一次重排操作,任何对渲染树的修改,都可能引发重排或者重绘。

    重排:

        当渲染树中一部分,因为元素的规模尺寸,布局,隐藏等改变而需要重新构建,这就称为回流,每个页面至少需要一次回流,就是在页面第一次加载的时候。

    重绘(repaint):

      当盒子的位置、大小以及其他属性,浏览器便把这些都按照各自的特性绘制一遍,将内容呈现在页面中。重绘是指一个元素外观的改变所触发的浏览器行为,浏览器会根据元素的新属性重新绘制,使元素呈现新的外观。

    重排和重绘的关系:在回流的时候,浏览器会使渲染树中受到影响的部分失效,并重新构造这部分渲染树,完成回流后,浏览器会重新绘制受影响的部分,该过程称为重绘,因此重排必定会引发重绘,但重绘不一定会引发重排。

    背景:

    有些重绘操作会比其他操作昂贵得多,比如你把一个body的子元素作了修改,不一定会导致大量的其他节点更新,但是你把一个元素移动到页面顶部去,可能就会导致其他全部节点进行重排操作。
    聪明的浏览器,因为渲染树的改变导致的重绘制或重排都可能代价很高,很多浏览器会对这个改动做很多的优化。
    一个策略就是不要立即做操作,而是批量进行,比如把你的脚本对DOM的修改放入一个队列,在队列所有操作结束后只需要进行一次绘制即可。
    但是有时候脚本可能会导致浏览器的批量优化无法进行,可能在清空队列之前就需要重新绘制页面,
    比如你通过脚本获取这些样式:offsetTop、offsetLeft、offsetWidth、offsetHeight ...,因为浏览器必须给你最新的值,所以当你进行取值操作的时候会立刻触发一次页面的绘制,
    这样本来可以批量修改样式然后一次性绘制的方法就无法使用了。

    如何减少重绘和重排

    1、不要一个地单独修改属性,最好通过ClassName来定义这些修改

    2、批量操作

       (1)、把对节点的大量操作放在页面之外,用documentFragment来做修改。

       (2)、clone节点,在clone之后的节点中做修改,然后直接替换掉以前的节点。

    var fragment = document.createDocumentFragment();
     
    var li = document.createElement('li');
    li.innerHTML = 'apple';
    fragment.appendChild(li);
     
    var li = document.createElement('li');
    li.innerHTML = 'watermelon';
    fragment.appendChild(li);
     
    document.getElementById('fruit').appendChild(fragment);

         (3)、通过display:none来隐藏节点(直接导致一次重排和重绘),做大量的修改,然后显示节点(又一次重排和重绘),总共只有两次重排。

    3、考虑到渲染树,一次修改会导致大量的绘制操作,比如绝对定位元素的动画就不会影响其他大部分元素。

    4、浏览器优化: 浏览器自己会维护1个队列,把所有会引起回流、重绘的操作放入这个队列,等队列中的操作到了一定的数量或者到了一定的时间间隔,浏览器就会flush队列,进行一个批处理,这样就会让多次的回流、重绘变成一次回流重绘。
    不要经常访问浏览器的flush队列属性;如果一定要访问,可以利用缓存,将访问的值存储起来,接下来使用就不会再引发回流。

    // 例如myElement元素沿对角线移动,每次移动一个像素。到500*500像素的位置结束。timeout循环体中可以这么做
    myElement.style.left = 1 + myElement.offsetLeft + 'px';
    myElement.style.top = 1 + myElement.offsetTop + 'px';
    if(myElement.offsetLeft >= 500){
      stopAnimation();
    }
    
    // 显然这种方法低效,每次移动都要查询偏移量,导致浏览器刷新渲染队列而不利于优化。好的办法是获取一次起始位置的值,然后赋值给一个变量。如下
    var current = myElement.offsetLeft;
    current++;
    myElement.style.left = current + 'px';
    myElement.style.top = current + 'px';
    if(myElement.offsetLeft >= 500){
      stopAnimation();
    }

    触发重排的条件:任何页面布局和几何属性的改变都会触发重排

      1、页面渲染初始化

      2、添加或删除可见的DOM元素

      3、元素位置的改变,或者使用动画

      4、元素尺寸大小的改变

      5、浏览器窗口尺寸的改变

      6、填充内容的改变

      7、读取某些元素属性

    触发重绘的条件:重绘发生在元素的可见的外观被改变,但并没有影响到布局的时候。

    重绘重排的代价:耗时,导致浏览器卡慢。

    未完,待续......
  • 相关阅读:
    怎样让人的一生价值最大
    [LeetCode][Java] Minimum Depth of Binary Tree
    KVC和KVO
    js获取单独一个checkbox是否被选中
    It's not a Bug, It's a Feature! (poj 1482 最短路SPFA+隐式图+位运算)
    超声波测距温度补偿
    系统封装接口层 cmsis_os
    STM32F4XX高效驱动篇2 I2C
    Stm32f103 ADC 学习笔记
    Stm32f103 DAC 学习笔记
  • 原文地址:https://www.cnblogs.com/zhishiyv/p/14648129.html
Copyright © 2020-2023  润新知