You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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>;
};

问题原因

  1. ResizeObserver监听逻辑缺陷:当前监听父容器,但未在组件卸载时断开监听,且闭包中的chart引用可能在后续尺寸变化时失效,导致resize()调用无响应;同时,父容器的尺寸变化可能未同步传递给图表容器。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 22:10:53