resizeobserver 是监听图表容器尺寸变化最可靠的方案,需监听直接包裹容器、确保其有明确宽高、每个图表配独立实例并节流回调;调用图表库 resize() 前须确认实例已初始化,且在组件卸载时及时清理 observer。

ResizeObserver 监听图表容器尺寸变化
直接用 ResizeObserver 是目前最可靠、无轮询、不依赖窗口 resize 的方案。它能精准捕获图表父容器的宽高变动,比监听 window.onresize 更准确——尤其当图表在折叠侧边栏、Tabs 切换、响应式 Grid 布局中时,window.onresize 根本不会触发。
注意:必须监听图表的**直接包裹容器**(比如一个 <div id="chart-container">),而不是图表 canvas 或 SVG 本身,否则可能因内部重绘导致重复回调或漏触发。<ul>
<li>确保容器有明确宽高(哪怕 <code>width: 100% + height: 400px),ResizeObserver 对 display: none 或未渲染的元素不生效
ResizeObserver 实例,避免多个图表共用一个 observer 时互相干扰回调顺序requestAnimationFrame 包裹),防止高频 resize 导致连续重绘卡顿ECharts / Chart.js 等库的 resize() 方法调用时机
绝大多数主流图表库都提供 resize() 方法,但它不是“自动适配”,而是需要你手动触发。常见错误是监听到尺寸变化后立刻调用 myChart.resize(),却没确认图表实例是否已初始化完成,结果报错 Cannot read property 'resize' of undefined。
正确做法是把 resize() 调用和图表初始化逻辑解耦,例如:
let myChart;
const initChart = () => {
myChart = echarts.init(document.getElementById('chart-container'));
// ... 配置项
};
const handleResize = () => {
if (myChart && myChart.resize) {
requestAnimationFrame(() => myChart.resize());
}
};
// 初始化后才启动 observer
initChart();
new ResizeObserver(handleResize).observe(document.getElementById('chart-container'));
-
echarts.init()必须在 DOM 元素挂载且可测量后执行;若图表在 Vue/React 异步组件里,需等mounted或useEffect完成后再 init - Chart.js v3+ 的
chart.resize()默认会重绘,但 v2 需要显式调用chart.update()才生效 - 如果图表用了
responsive: true(Chart.js)或adaptive: true(ECharts 5.4+),仍需手动resize(),因为这些配置只影响初始化行为,不接管后续尺寸变更
Vue / React 中的常见陷阱:ref 未就绪或组件卸载后调用 resize
在响应式框架里,最容易出问题的是:observer 回调触发时,组件已销毁(比如路由跳转、v-if 切换),但 resize() 还在试图操作一个不存在的图表实例,控制台报错 Cannot call resize on destroyed instance 或直接白屏。
- Vue 3 Composition API 中,务必在
onBeforeUnmount里调用observer.disconnect()并清空图表实例 - React 函数组件中,
useEffect的 cleanup 函数必须返回observer.disconnect(),且 resize 回调里加if (!chartRef.current) return防止空引用 - 不要把
ResizeObserver实例挂到全局或父组件 state 上——它和具体图表 DOM 强绑定,跨组件复用极易引发内存泄漏
兜底方案:window.resize + 容器尺寸比对(兼容老浏览器)
如果项目还需支持 Safari ResizeObserver 不可用,就得降级。但别直接监听 window.onresize 后无脑调 resize()——这会导致图表在页面滚动、弹窗打开时误刷新。
更稳妥的做法是:定时(如 300ms)检查图表容器的 getBoundingClientRect(),仅当宽或高发生实质性变化(> 1px)时才触发重绘:
let lastSize = { w: 0, h: 0 };
const checkAndResize = () => {
const el = document.getElementById('chart-container');
const rect = el.getBoundingClientRect();
if (Math.abs(rect.width - lastSize.w) > 1 || Math.abs(rect.height - lastSize.h) > 1) {
lastSize = { w: rect.width, h: rect.height };
myChart?.resize?.();
}
};
window.addEventListener('resize', checkAndResize);
// 首次立即检查
checkAndResize();
这个方案性能尚可,但要注意:如果容器使用了 CSS transform 缩放,getBoundingClientRect() 返回的是视觉尺寸,可能和实际布局尺寸不一致,此时需额外处理 scale 因子。
真正难的不是监听尺寸,而是确保 resize 调用发生在图表实例存活、DOM 可测量、且不与其他生命周期冲突的精确时间点——这三个条件同时满足,才算稳。











