ResizeObserver是浏览器原生专治元素尺寸变化的方案,它按需监听具体DOM元素、批量回调、不阻塞渲染,且具备自动去重和防循环机制;必须显式调用observe(),并在组件卸载时disconnect(),SSR中需确保仅客户端执行。

直接用 ResizeObserver,别轮询、别监听 window.resize、也别靠 MutationObserver 猜尺寸——它就是浏览器原生给的、专治“元素大小变了但 JS 不知道”的方案。
为什么不能用 window.resize 监听容器变化
因为 window.resize 只在视口(viewport)大小变化时触发,和你页面里某个 <div class="chart"> 被 flex 布局挤窄了、或者被 CSS 动画拉宽了完全无关。常见错误现象是:图表容器明明变小了,ECharts 却没重绘;侧边栏折叠后内容区没自适应,留白或溢出。<p>更糟的是,如果多个组件都绑了 <code>window.resize,每次缩放都会触发所有回调,性能雪崩。而 ResizeObserver 是按需监听、批量回调、不阻塞渲染。
- 只监听你明确传进去的 DOM 元素,比如
document.querySelector('.card') - 回调里拿到的是
entry.contentRect.width,单位像素,反映内容盒实际尺寸 - 浏览器自动去重、防循环:哪怕你在回调里改了元素宽度,也不会立刻再次触发(有
lastReportedSize缓存机制)
ResizeObserver 必须传回调,且要手动 observe()
它不像 addEventListener 那样注册即生效,必须显式调用 observe(target) 才开始监听。漏掉这步,控制台静悄悄,什么都不会发生。
立即学习“前端免费学习笔记(深入)”;
典型写法:
const ro = new ResizeObserver((entries) => {
for (const entry of entries) {
console.log(entry.contentRect.width); // ✅ 正确读取
}
});
ro.observe(document.getElementById('my-box')); // ✅ 必须调用
容易踩的坑:
- 传入
null或不存在的元素 → 控制台报错Failed to execute 'observe' on 'ResizeObserver': The target must be an instance of Element - 在 Vue/React 组件卸载前没调用
ro.disconnect()→ 内存泄漏,回调还在执行但 DOM 已销毁 - 误以为能监听
window或document→ 浏览器直接抛错,ResizeObserver只接受单个具体元素节点
动态字体缩放时,别用 vw,优先用 ResizeObserver + 容器宽度
vw 是基于视口,不是父容器。如果你的文本在 max-width: 600px 的卡片里,font-size: 4vw 在 1920px 屏幕下会变成 76.8px,远超卡片承载能力。
真正可控的做法是监听卡片本身宽度,再算比例缩放:
const ro = new ResizeObserver((entries) => {
const width = entries[0].contentRect.width;
const scale = Math.min(1, Math.max(0.6, width / 600));
entry.target.style.fontSize = `${16 * scale}px`;
});
ro.observe(document.querySelector('.responsive-text'));
注意点:
- 用
contentRect.width,不是getBoundingClientRect().width—— 后者可能触发同步布局(forced reflow),尤其在循环中读取时 - 加
Math.min/max限幅,避免极端缩放(比如容器缩到 10px 宽,字体不能真变成 0.26px) - 如果项目要兼容旧版 Safari(contentBoxSize 可能不可用,得 fallback 到
getBoundingClientRect(),但务必只读一次
React/Vue 中使用要防重复初始化和内存泄漏
在组件挂载时创建 ResizeObserver,但若组件频繁销毁重建(比如路由切换、列表项复用),不清理就会累积多个 observer 实例,占用内存且回调乱跑。
React 示例(useEffect 清理):
useEffect(() => {
const ro = new ResizeObserver(...);
ro.observe(ref.current);
return () => ro.disconnect(); // ✅ 关键:卸载时断开
}, []);
Vue 示例(onUnmounted):
onMounted(() => {
const ro = new ResizeObserver(...);
ro.observe(el.value);
onUnmounted(() => ro.disconnect()); // ✅ 同样关键
});
最容易被忽略的一点:SSR(服务端渲染)项目中,ResizeObserver 无法在服务端运行,必须确保初始化逻辑只在客户端执行,比如包裹在 if (typeof window !== 'undefined') 里,否则构建时报错或 hydration 失败。



















