测试回流与重绘

先说一下得出的结论:

获取定位时并不一定会回流
这取决于前面是否有可能导致几何信息变化的操作

一、测试一下下面几种情况

1. 连续修改 - 注意这些修改都是会影响元素尺寸或位置的操作

stopBtn.style.position = 'relative';
stopBtn.style.width = '100px'
stopBtn.style.height = '200px'
stopBtn.style.left = '10px'
stopBtn.style.top = '10px' 

结果是一次 recalculate style - layout

2. 改一次查一次

stopBtn.style.position = 'relative';
stopBtn.style.width = '100px'
console.log(stopBtn.offsetWidth);
stopBtn.style.height = '200px'
console.log(stopBtn.offsetHeight);
stopBtn.style.left = '10px'
console.log(stopBtn.offsetLeft);
stopBtn.style.top = '10px' // 一次recalculate style -> layout
console.log(stopBtn.offsetTop);
结果layout了四次

结果是4次layout

3. 写完再一次性读

stopBtn.style.position = 'relative';
stopBtn.style.width = '100px'
stopBtn.style.height = '200px'
stopBtn.style.left = '10px'
stopBtn.style.top = '10px'
console.log(stopBtn.offsetWidth);
console.log(stopBtn.offsetHeight);
console.log(stopBtn.offsetLeft);
console.log(stopBtn.offsetTop);
image.png

结果是一次 recalculate style - layout

4. 同一行先读再写

stopBtn.style.position = 'relative';
stopBtn.style.width = stopBtn.offsetWidth + 100 + 'px';

image.png

结果是 2次 layout,读 offsetWidth 时会layout是因为前面有一个修改position的操作。
当我把这行修改position的代码删掉时,就只会layout一次,如下:

image.png

或者当我把修改position改为修改color,也只会layout一次:

image.png

5. 增加一次修改

stopBtn.style.position = 'relative';
stopBtn.style.width = stopBtn.offsetWidth + 100 + 'px';
stopBtn.style.height = '300px'
image.png

仍然是2次layout

二、 结论

所以获取定位时是否会回流取决于前面是否有可能导致几何信息变化的操作
如果在读offsetWidth之前改的仅是color,那么不会导致layout:

stopBtn.style.color = 'red';
console.log(stopBtn.offsetWidth);
image.png

三. 验证一下

1. 修改背景色 + getBoundingClientRect

stopBtn.style.backgroundColor = 'blue';
stopBtn.style.backgroundColor = 'blue';
console.log(stopBtn.getBoundingClientRect());
没有Layout

都只有 Recalculate StylegetBoundingClientRect 时并没有触发 layout,因为前面改的是背景色

2. 修改背景色 + 文本 + getBoundingClientRect

 stopBtn.style.backgroundColor = 'blue';
 stopBtn.innerText = 'wxmwxm'; // Layout是由于这里
stopBtn.style.backgroundColor = 'blue';
stopBtn.innerText = 'wxmwxm';
console.log(stopBtn.getBoundingClientRect());
有一次Layout

这两种都是上面的顺序:一次Recalculate StyleLayout

3. 调换一下顺序:

stopBtn.style.backgroundColor = 'blue';
console.log(stopBtn.getBoundingClientRect());
stopBtn.innerText = 'wxmwxm';  // 这里Recalculate Style (Recalculation Forced) -> Schedule Style Recalculation
            //  -> Recalculate Style (First Invalidated) ->Layout (First Layout Invalidation)
有2次 Recalculate style 和一次 Layout

4. 加一个改变颜色:

stopBtn.style.backgroundColor = 'blue';
console.log(stopBtn.getBoundingClientRect());
stopBtn.innerText = 'wxmwxm'; // 这里Recalculate Style (Recalculation Forced)
stopBtn.style.color = 'red'; // 这里Schedule Style Recalculation -> Recalculate Style -> Layout
仍然是2次 Recalculate style 和一次 Layout

5. 再加一行 getBoundingClientRect:

stopBtn.style.backgroundColor = 'blue';
console.log(stopBtn.getBoundingClientRect());
stopBtn.innerText = 'wxmwxm'; // 这里 Recalculate style (Recalculation Forced 强制重新计算)
stopBtn.style.color = 'red'; // 这里 Schedule Style Recalculation--计划重新计算

// getBoundingClientRect之前:Recalculate style (Recalculation Forced 、First Invalidated) 
// 和 Layout (First Layout Invalidation)
console.log(stopBtn.getBoundingClientRect());
一次layout,因为最后一个getBoundingClientRect之前有一个修改innerText 操作

四. 最后看下可能导致layout的操作(仅举例说明)

注意小红三角的提示
image.png
image.png
image.png
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容