27

有没有办法在getBoundingClientRect()没有实际计算的情况下检测元素的矩形何时发生变化getBoundingClientRect()?像“脏旗”之类的东西?天真地,我假设在浏览器的内部工作中一定有这样的机制,但我一直无法找到暴露在 DOM API 中的这个东西。也许有办法用 MutationObservers 做到这一点?

我的应用程序是一个 Web 组件,它将 DOM 元素转换为图形的节点,并将边缘绘制到全屏画布上。见这里

现在,我正在调用getBoundingClientRect()每个元素,每个动画帧帧一次,即使没有任何变化。感觉很贵 我通常在一台功能强大的计算机上以 60 fps 的速度获得 %15-%50 的 CPU 使用率。

有谁知道这样的事情?你认为期待这样的事情合理吗?这种事情可行吗?以前有没有提出过?

4

1 回答 1

11

正如上面的评论中提到的。您正在寻找的 API 是:ResizeObserverIntersectionObserver. 但是,有几点需要注意:

  • ResizeObserver只有当观察到的元素改变大小时才会触发。它基本上只会为您提供正确的宽度和高度值。
  • 两者ResizeObserverIntersectionObserver应该不会阻塞油漆
  • ResizeObserver将在布局之后但在绘制之前触发,这基本上使它感觉同步。
  • IntersectionObserver异步触发。

如果您需要位置变化跟踪怎么办

这就是IntersectionObserver为之而生的。它通常可以用于可见性检测。这里的问题是,IntersectionObserver只有当交叉点的比率发生变化时才会触发。这意味着如果一个小的孩子在一个较大的容器 div 中四处移动,并且您跟踪父级和子级之间的交集,则除非孩子进入或退出父级,否则您将不会收到任何事件。

您仍然可以跟踪元素何时移动。这是如何:

  • 首先使用 测量要跟踪的元素的位置getBoundingClientRect
  • 插入一个 div 作为 body 的绝对定位的直接子元素,该子元素恰好位于被跟踪元素的位置。
  • 开始跟踪这个 div 和原始元素之间的交集。
  • 交叉点应从 1 开始。每当它变为其他内容时:
    • 使用 重新测量元素getBoundingClientRect
    • 触发位置/大小更改事件
    • 将自定义 div 的样式更新到元素的新位置。
    • 观察者应该再次以 1 的交叉比率再次触发,这个值可以忽略。

注意:这种技术也可以用于更有效的 polypill,ResizeObserver这是一个比IntersectionObserver. 常用的 polyfill 依赖于MutationObserver哪个效率低得多。

于 2020-01-25T01:46:36.413 回答