ResizeObserver仅触发一次元素尺寸变更,图表无法随侧边栏收缩
问题:折叠侧边栏后重新打开,ECharts图表无法收缩
点击按钮显示图表,图表首次实例化时会在其父容器上设置ResizeObserver。应用带有可折叠侧边栏,折叠侧边栏时图表能正常扩展填充空间,但重新打开侧边栏时,图表不会收缩回去。
相关样式
父容器
<div id={"chartContainer"} style={{ width: "100%", height: "100%", border: "2px solid yellow", }} />
图表容器
<div ref={chartRef} style={{ width: "100%", height: "80vh" }}></div>
组件代码
export const Chart = () => { const chartRef = useRef<HTMLDivElement>(null); useEffect(() => { let chart: ECharts | undefined; if (chartRef.current !== null) { chart = init(chartRef.current, null, { renderer: "svg" }); } const parentContainer: HTMLDivElement = document.querySelector("#chartContainer"); new ResizeObserver(() => { chart.resize(); }).observe(parentContainer); return () => { chart?.dispose(); }; }, []); useEffect(() => { if (chartRef.current !== null) { const chart = getInstanceByDom(chartRef.current); chart?.setOption(option); } }, [option]); return <div ref={chartRef} style={{ width: "100%", height: "80vh" }}></div>; };
问题原因
- ResizeObserver监听逻辑缺陷:当前监听父容器,但未在组件卸载时断开监听,且闭包中的
chart引用可能在后续尺寸变化时失效,导致resize()调用无响应;同时,父容器的尺寸变化可能未同步传递给图表容器。 - Flex布局尺寸传递延迟:父容器嵌套在flex元素中,侧边栏切换时,父容器的宽度变化可能未被ResizeObserver及时捕获,或ECharts内部的尺寸缓存未更新。
修复方案
方案1:监听图表自身容器并清理Observer
将ResizeObserver的监听目标改为图表容器自身,同时在组件卸载时断开监听,确保引用始终有效:
export const Chart = () => { const chartRef = useRef<HTMLDivElement>(null); const resizeObserverRef = useRef<ResizeObserver | null>(null); useEffect(() => { let chart: ECharts | undefined; if (chartRef.current) { chart = init(chartRef.current, null, { renderer: "svg" }); // 监听图表容器的尺寸变化 resizeObserverRef.current = new ResizeObserver(() => { chart?.resize(); }); resizeObserverRef.current.observe(chartRef.current); } return () => { // 清理Observer和图表实例 resizeObserverRef.current?.disconnect(); chart?.dispose(); }; }, []); useEffect(() => { if (chartRef.current) { const chart = getInstanceByDom(chartRef.current); chart?.setOption(option); } }, [option]); return <div ref={chartRef} style={{ width: "100%", height: "80vh" }}></div>; };
方案2:侧边栏状态变化时强制触发resize
如果ResizeObserver仍未生效,可在侧边栏状态切换时主动调用图表的resize()方法。假设侧边栏状态由父组件的isSidebarOpen管理:
// 父组件中 const [isSidebarOpen, setIsSidebarOpen] = useState(true); // Chart组件接收状态props export const Chart = ({ isSidebarOpen }: { isSidebarOpen: boolean }) => { const chartRef = useRef<HTMLDivElement>(null); // 侧边栏状态变化时强制更新尺寸 useEffect(() => { const chart = getInstanceByDom(chartRef.current); chart?.resize(); }, [isSidebarOpen]); // 其余代码同原组件... };
方案3:确保flex布局配置正确
检查父容器所在的flex容器:
- 父容器的直接父元素需设置
display: flex - 父容器自身设置
flex: 1,确保它能随容器宽度变化自动调整尺寸
内容的提问来源于stack exchange,提问作者MKF
相关产品推荐
相关产品推荐

