ResizeObserver:类似于元素的 document.onresize

在 ResizeObserver 之前,您必须将监听器附加到文档的 resize 事件,以在视口尺寸更改时获取通知。在活动中 然后,您必须找出哪些元素受到了 并调用特定日常安排以做出适当反应。如果您需要 调整大小后元素的新尺寸,您必须调用 getBoundingClientRect() 或 getComputedStyle(),这可能会导致布局 如果您不负责批处理所有读取操作和所有操作,就会出现抖动。 写入。

这甚至没有涵盖在没有主要元素的情况下元素会改变其大小的情况 窗口大小例如,附加新的子节点、设置一个 元素的 display 样式更改为 none,或者类似的操作可以更改 元素、其同级元素或祖先实体。

正因如此,ResizeObserver 才是有用的基元。它会根据 任何观察到的元素的大小,无论发生变化的原因是什么。 它还提供对所观察元素的新大小的访问权限。

所有带我们前面提到的 Observer 后缀的 API 共用一个简单的 API 设计。ResizeObserver也不例外。您创建一个 ResizeObserver 对象 并向构造函数传递一个回调。系统会向该回调函数传递一个 ResizeObserverEntry 对象(每个观察到的元素一个条目), 包含元素的新尺寸。

var ro = new ResizeObserver(entries => {
  for (let entry of entries) {
    const cr = entry.contentRect;

    console.log('Element:', entry.target);
    console.log(`Element size: ${cr.width}px x ${cr.height}px`);
    console.log(`Element padding: ${cr.top}px ; ${cr.left}px`);
  }
});

// Observe one or multiple elements
ro.observe(someElement);

一般来说, ResizeObserverEntry 通过名为 contentRect,该函数会返回 DOMRectReadOnly 对象。内容框是用来放置内容的框。时间是 边框减去内边距

请务必注意,尽管ResizeObserver 报告 contentRect 和内边距后,它只会观察 contentRect。 请勿将 contentRect 与元素的边界框混淆。边界 根据 getBoundingClientRect() 的报告,box 是一个包含 整个元素及其后代。SVG 不遵守此规则 ResizeObserver 会报告边界框的尺寸。

自 Chrome 84 起,ResizeObserverEntry 有了三项新属性,可提供更多 。这两个属性都会返回一个 ResizeObserverSize 对象包含 blockSize 属性和 inlineSize 属性。这个 与在调用回调函数时观察到的元素相关的信息。

  • borderBoxSize
  • contentBoxSize
  • devicePixelContentBoxSize

所有这些项都会返回只读数组,因为我们希望将来能够 它们可以支持具有多个 fragment 的元素,这些 fragment 出现在 多列情景。目前,这些数组将只包含一个元素。

针对这些属性的平台支持有限,但 Firefox 已经 支持 前两项。

该规范规定,ResizeObserver 应处理所有调整大小事件 绘制之前和布局之后这会使 ResizeObserver 的回调成为 更改网页布局的理想位置。因为ResizeObserver 处理发生在布局和绘制之间,这样做只会使 而不是绘制

您可能会问自己:如果我更改了观察对象的大小,会出现什么情况? ResizeObserver 回调中的元素吗?答案是:触发 立即再次调用该回调函数。幸运的是,ResizeObserver具有 机制来避免无限回调循环和循环依赖项。更改将 仅当调整后的元素在 DOM 中更深时,才会在同一帧中处理 与在上一个回调中处理的 shallowest 元素相比。 否则,它们会被推迟到下一帧。

ResizeObserver 允许您做的一件事是实现元素级 。通过观察元素,您可以命令式地定义您的 设计断点和更改元素的样式。在以下 example,第二个框 将会根据其宽度更改边框半径。

const ro = new ResizeObserver(entries => {
  for (let entry of entries) {
    entry.target.style.borderRadius =
        Math.max(0, 250 - entry.contentRect.width) + 'px';
  }
});
// Only observe the second box
ro.observe(document.querySelector('.box:nth-child(2)'));

另一个有趣的例子是聊天窗口。出现的问题 即滚动定位。为避免 如果窗口固定在 会话,其中会显示最新邮件。此外,任何类型的布局 (假设手机从横向转为纵向,或者从横向转为纵向) 实现同样的目标。

ResizeObserver 允许您编写一段单一代码, 两种情况。窗口大小调整是 ResizeObserver 可以执行的操作 根据定义进行捕获,但调用 appendChild() 也会调整该元素的大小 (除非已设置 overflow: hidden),因为它需要为新的 元素。考虑到这一点,只需很少的代码行,即可实现所需的 效果:

const ro = new ResizeObserver(entries => {
  document.scrollingElement.scrollTop =
    document.scrollingElement.scrollHeight;
});

// Observe the scrollingElement for when the window gets resized
ro.observe(document.scrollingElement);

// Observe the timeline to process new messages
ro.observe(timeline);

挺酷的,对吧?

在这里,我可以添加更多代码来处理用户滚动网页的情况 并希望在用户收到新消息时一直滚动消息 。

另一个用例是任何具有自己的布局的自定义元素。 在ResizeObserver之前,您没法通过可靠的方法收到 尺寸更改,以便重新排列其子项。

Interaction to Next Paint (INP) 指标可衡量 网页对用户互动的整体响应情况。如果网页的 INP 为 “优质”阈值,即 200 可以说网页能够可靠地响应 用户与应用之间的互动行为

虽然事件回调的运行时间是为响应 用户互动会显著增加互动的总延迟时间 这并不是 INP 需要考虑的唯一方面。INP 还会考虑 对互动进行下一次绘制所用的时间。这是 更新用户所需的渲染工作所花费的时间 响应互动操作来完成。

就 ResizeObserver 而言,这很重要,因为 ResizerObserver 实例运行发生在渲染工作之前。这个 是设计使然,因为回调中发生的工作必须纳入 因此这项工作很可能需要更改 界面。

根据 ResizeObserver 中的要求尽量减少渲染工作 因为过度渲染工作可能会导致浏览器出现 在处理重要事务方面有延迟。例如,如果任意互动具有 回调,以确保您执行了ResizeObserver 以提供尽可能顺畅的体验:

  • 确保 CSS 选择器尽可能简单,从而避免 过多的样式重新计算工作。 样式重新计算发生在布局之前,并且复杂的 CSS 选择器可能 延迟布局操作。
  • 避免在 ResizeObserver 回调中执行任何可能会触发的工作 强制自动重排
  • 通常,更新网页布局所需的时间 页面上 DOM 元素的数量。无论网页是否使用 ResizeObserver 时,在 ResizeObserver 回调中完成的工作可以变为 网页结构复杂程度的提升会显著增加。

ResizeObserver 支持所有主要语言 浏览器 并且提供了一种高效的方式来监控元素上元素的大小调整 。但请注意,不要让这个强大的 API 呈现太多延迟。

阅读余下内容
 

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注


京ICP备12002735号