resizeobserver 是监听元素尺寸变化最直接可靠的方式,支持 flex 挤压、侧边栏折叠等场景;须监听已挂载 dom 节点,vue 在 onmounted、react 在 useeffect 中安全调用;contentrect 为内容盒尺寸,offsetwidth 含 padding/border,需按需选用;多容器监听应避免重复重绘,卸载时必须 disconnect;天然支持 shadow dom、iframe 和嵌套布局。
用 resizeobserver 监听元素尺寸变化,是实现复杂自适应布局最直接、最可靠的方式。它不依赖窗口缩放,能精准捕获 flex 布局挤压、侧边栏折叠、拖拽面板拉伸、css 动画缩放等任意导致尺寸变动的场景。
监听目标要明确:只观察真实挂载的 DOM 元素
ResizeObserver.observe() 必须传入已渲染的 Element 节点,不能是 null、ref 对象或未挂载的占位符。常见错误是在组件初始化阶段就调用 observe,此时容器 DOM 还未生成。
- Vue 中应在 onMounted 钩子内执行,加判空防护:
if (chartRef.value) observer.observe(chartRef.value) - React 中应在 useEffect 中处理,并包裹
if (typeof window !== 'undefined')避免 SSR 报错 - 监听前建议校验节点类型:
targetElement && targetElement.nodeType === 1
回调里拿对尺寸:contentRect vs offsetWidth 要分清
entry.contentRect.width 是内容盒宽度(不含 padding 和 border),而 offsetWidth 包含 padding + border。两者数值常不一致,混用会导致布局错位。
- 若需匹配视觉尺寸(比如控制卡片换行断点),推荐用
target.getBoundingClientRect().width - 若做图表重绘、Canvas 缩放等纯内容适配,
contentRect更干净,避免样式干扰 - 统一项目中 box-sizing 策略:全部设为
border-box时,contentRect 宽度 = width + 左右 padding;保持一致才好建模
多容器监听要防性能雪崩
一个 ResizeObserver 实例可同时观察多个元素,但回调中不能对每个 entry 都重复初始化图表、重绘或触发昂贵计算。
- 避免反模式:在回调里遍历 entries,对每个
entry.target都调echarts.init()—— 任一容器变,全部重绘 - 推荐做法:每个图表容器独享一个 ResizeObserver,或在回调中按 target.id 分支处理,仅更新对应实例
- 组件卸载时务必调用
observer.disconnect(),防止内存泄漏
适配特殊布局:画布比例、iframe、嵌套容器
ResizeObserver 天然支持 shadow DOM、iframe 子页面、flex/gird 嵌套结构,这是 window.resize 完全做不到的。
- 保持 Canvas 比例:监听父容器
contentRect,取Math.min(width, height)作为画布正方形边长,再设置 canvas.style - iframe 内部元素:在 iframe 的 document 上创建 ResizeObserver,监听其内部容器,无需跨域通信
- 微前端场景:子应用可独立监听自身容器尺寸,父壳无需干预,解耦清晰










