【问题标题】:How to wait for DOM changes to render? (MutationObserver doesn't work)如何等待 DOM 更改呈现? (MutationObserver 不起作用)
【发布时间】:2020-01-11 01:53:54
【问题描述】:

我有一棵 DOM 节点树,并删除了一些子节点。 我想确定 DOM 树的更新大小。

MutationObserver 不起作用,因为它会通知 DOM 模型更改,但渲染尚未真正完成,因此尺寸尚未更新。

有一些老套的方法可以做到这一点(setTimeout(delay) 或多个嵌套的 requestAnimationFrame()),但我不想在以后遇到意外的大小问题。

有什么简单的方法可以做到这一点吗?

【问题讨论】:

  • 相当肯定requestAnimationFrame 后跟setTimeout 这样做的方式,虽然我也希望有更好的方式
  • ResizeObserver,但并非所有浏览器都支持。

标签: javascript jquery html dom


【解决方案1】:

盒子布局的更新,也就是“reflow”可以是triggered synchronously,并且不需要“完整渲染”。 您可以查看this answer,了解有关渲染操作同步性的更多详细信息。

因此,在您的情况下,您可以在更新 DOM 后直接获取元素的新尺寸,因为这种尺寸获取本身会触发重排;甚至没有必要使用 MutationObserver。

const elem = document.getElementById('elem');
console.log('initial', elem.offsetHeight);
elem.querySelectorAll('p:not(.notme)').forEach(el=>el.remove());
// getting '.offsetHeight' triggers a reflow
console.log('after removing', elem.offsetHeight);
<div id="elem">
  <p>Hello</p>
  <p>Hello</p>
  <p>Hello</p>
  <p>Hello</p>
  <p>Hello</p>
  <p class="notme">Hello</p> 
</div>

虽然要注意,触发重排在性能方面有一些成本,所以如果你担心其他事情之后也可能修改 DOM,你可能想等待绘画事件循环迭代,在调用之前使用 requestAnimationFrame触发它的方法。

const elem = document.getElementById('elem');
console.log('initial', elem.offsetHeight);
elem.querySelectorAll('p:not(.notme)').forEach(el=>el.remove());

// wait the painting frame in case other operations also modify the DOM
requestAnimationFrame(()=> {
  console.log('after removing', elem.offsetHeight);
});
<div id="elem">
  <p>Hello</p>
  <p>Hello</p>
  <p>Hello</p>
  <p>Hello</p>
  <p>Hello</p>
  <p class="notme">Hello</p> 
</div>

Ps:对于那些仍然对这个 XY 问题的 Y 感兴趣的人,你可以看看 this Q/A,它演示了即将推出的 requestPostAnimationFrame 的使用并提供了一个猴子补丁。

【讨论】:

  • 有趣的信息。移除 DOM 元素后,在链式then() 块中调用的所有回流触发方法(offsetHeight、computedStyle、boundingClientRect)都没有更新的值。似乎只有 2+ rAF() 调用或 setTimeout(7ms) 返回正确的。根据您在答案中提到的 3 部分重绘过程,该值似乎在第二部分回流之后更新。之后是否有一些 CSS 规则会对其进行更改,例如选择器 .class:first
  • 请在minimal reproducible example 上发布您所拥有的内容。这些 getter 和方法将始终具有更新的值,因此您的设置中必须有一些东西确实会改变元素的高度在您获得这些值之后
猜你喜欢
  • 2019-08-21
  • 1970-01-01
  • 1970-01-01
  • 2018-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-12
相关资源
最近更新 更多