ResizeObserver
ResizeObserver 接口报告 Element 内容框或边框框尺寸的更改,或 SVGElement 的边界框的更改。
注意:内容框是可以放置内容的框,即边框框减去内边距和边框宽度。边框框包含内容、内边距和边框。请参阅 盒模型 以获得进一步解释。
构造函数
ResizeObserver()-
创建并返回一个新的
ResizeObserver对象。
实例属性
无。
实例方法
ResizeObserver.disconnect()-
取消观察特定观察器所有被观察的
Element目标。 ResizeObserver.observe()-
开始观察指定的
Element。 ResizeObserver.unobserve()-
停止观察指定的
Element。
示例
在 resize-observer-text.html (查看源代码) 示例中,我们使用 resize observer 在滑块值改变导致包含的 <div> 宽度改变时,更改标题和段落的 font-size。这表明您可以响应元素大小的变化,即使这些变化与视口无关。
我们还提供了一个复选框来打开和关闭观察器。如果关闭,文本将不会响应 <div> 宽度变化而改变。
JavaScript 代码如下
const h1Elem = document.querySelector("h1");
const pElem = document.querySelector("p");
const divElem = document.querySelector("body > div");
const slider = document.querySelector('input[type="range"]');
const checkbox = document.querySelector('input[type="checkbox"]');
divElem.style.width = "600px";
slider.addEventListener("input", () => {
divElem.style.width = `${slider.value}px`;
});
const resizeObserver = new ResizeObserver((entries) => {
for (const entry of entries) {
if (entry.contentBoxSize) {
const contentBoxSize = entry.contentBoxSize[0];
h1Elem.style.fontSize = `${Math.max(
1.5,
contentBoxSize.inlineSize / 200,
)}rem`;
pElem.style.fontSize = `${Math.max(
1,
contentBoxSize.inlineSize / 600,
)}rem`;
} else {
h1Elem.style.fontSize = `${Math.max(
1.5,
entry.contentRect.width / 200,
)}rem`;
pElem.style.fontSize = `${Math.max(1, entry.contentRect.width / 600)}rem`;
}
}
console.log("Size changed");
});
resizeObserver.observe(divElem);
checkbox.addEventListener("change", () => {
if (checkbox.checked) {
resizeObserver.observe(divElem);
} else {
resizeObserver.unobserve(divElem);
}
});
观察错误
遵循规范的实现会在绘制前(即在帧显示给用户之前)调用 resize 事件。如果有任何 resize 事件,将重新评估样式和布局 — 这反过来可能会触发更多 resize 事件。由循环依赖引起的无限循环通过在每次迭代中仅处理 DOM 中更深的元素来解决。不满足此条件的 resize 事件将推迟到下一个绘制,并在 Window 对象上触发一个错误事件,带有明确定义的字符串消息
ResizeObserver loop completed with undelivered notifications.
请注意,这仅能防止用户代理锁定,而不能防止无限循环本身。例如,以下代码将导致 divElem 的宽度无限增长,并在每个帧中在控制台中重复出现上述错误消息
const divElem = document.querySelector("body > div");
const resizeObserver = new ResizeObserver((entries) => {
for (const entry of entries) {
entry.target.style.width = `${entry.contentBoxSize[0].inlineSize + 10}px`;
}
});
resizeObserver.observe(divElem);
window.addEventListener("error", (e) => {
console.error(e.message);
});
只要错误事件不无限触发,resize observer 就会稳定下来并产生一个稳定、可能正确的布局。但是,访问者可能会看到短暂的损坏布局,因为本应在一个帧中发生的一系列更改却发生在多个帧中。
如果您想防止这些错误,解决方案取决于您的预期效果。如果您确实打算实现无限循环,只需将 ResizeObserver 回调中的重置代码推迟到浏览器重绘之后即可。您可以将其放入 requestAnimationFrame 回调中。
const divElem = document.querySelector("body > div");
const resizeObserver = new ResizeObserver((entries) => {
requestAnimationFrame(() => {
for (const entry of entries) {
entry.target.style.width = `${entry.contentBoxSize[0].inlineSize + 10}px`;
}
});
});
resizeObserver.observe(divElem);
window.addEventListener("error", (e) => {
console.error(e.message);
});
如果您无意实现无限循环,则应确保您的重置代码不会触发 resize observer 回调。有多种方法可以实现这一点,例如设置一个“预期大小”,如果大小已经达到该值则不进行重置。
const divElem = document.querySelector("body > div");
const expectedSizes = new WeakMap();
const resizeObserver = new ResizeObserver((entries) => {
requestAnimationFrame(() => {
for (const entry of entries) {
const expectedSize = expectedSizes.get(entry.target);
if (entry.contentBoxSize[0].inlineSize === expectedSize) {
continue;
}
const newSize = entry.contentBoxSize[0].inlineSize + 10;
entry.target.style.width = `${newSize}px`;
expectedSizes.set(entry.target, newSize);
}
});
});
resizeObserver.observe(divElem);
window.addEventListener("error", (e) => {
console.error(e.message);
});
规范
| 规范 |
|---|
| Resize Observer(调整大小观察器) # resize-observer-interface |
浏览器兼容性
加载中…
另见
- 学习:盒模型
PerformanceObserverIntersectionObserver(属于 Intersection Observer API)- 即将推出的 容器查询 可能是实现响应式设计的一个可行替代方案。