Vue中keep-alive缓存ECharts图表时宽高异常,本质是实例挂载在尺寸未就绪的DOM上;解决关键是activated钩子调resize、v-if控制渲染、ResizeObserver精准监听或启用vue-echarts的autoresize。
Vue 组件用 keep-alive 缓存后,ECharts 图表在 Tab 切换回来时宽高异常(比如显示为空白、宽度固定为 100px、resize 不触发),本质是图表实例仍挂载在已脱离文档流或尺寸未就绪的 DOM 上,而 resize 监听逻辑没同步更新上下文。解决关键不是“重绘”,而是“确保 resize 调用发生在正确时机、作用于正确实例、依据正确尺寸”。
keep-alive 组件不会走 mounted/destroyed,但会触发 activated 和 deactivated。切回页面时,DOM 已恢复可见且尺寸可读,此时调用 chart.resize() 最稳妥。
activated 钩子中检查 chart 实例是否存在,存在则立即执行 resize()
deactivated 中销毁 chart(除非明确需要释放资源),保留实例即可nextTick 确保 DOM 渲染完成后再获取尺寸,例如:this.$nextTick(() => this.chart?.resize())
比起 v-show 或 display: none,v-if 能真正卸载/重建组件,让 ECharts 在每次显示时都重新初始化,天然规避尺寸残留问题。
v-if="activeTab === 'chart1'"
ref 和生命周期,互不干扰keep-alive 包裹整个 Tab 内容区域,而非单个图表组件全局 window.resize 容易被缓存组件干扰(如监听器还在跑,但目标 DOM 尺寸为 0),而 ResizeObserver 只观察特定容器,精准响应自身变化。
mounted 中创建 observer,监听图表容器元素:const ro = new ResizeObserver(() => this.chart?.resize())
beforeUnmount(Vue 3)或 beforeDestroy(Vue 2)中调用 ro.disconnect()
如果你用的是 vue-echarts(v6+),它原生支持 autoresize 属性,比手写监听更可靠。
<v-chart :autoresize="{ throttle: 160 }" :option="option" />
throttle 防抖值建议设为 100–200ms,兼顾响应性和性能width: 100%; height: 400px; 或使用 flex 布局撑满)