React 中 ECharts 多实例窗口调整大小失效的解决方案

React 中 ECharts 多实例窗口调整大小失效的解决方案

react 应用中渲染多个 echarts 图表时,如果仅使用 window.onresize 监听窗口大小变化来触发图表重绘,会导致只有最后一个注册的图表能够响应。这是因为 window.onresize 是一个事件属性,每次赋值都会覆盖前一个。解决此问题的正确方法是使用 window.addeventlistener 为每个图表实例添加独立的 resize 事件监听器,并确保在组件卸载时清理这些监听器,从而保证所有图表都能正确响应窗口大小变化。

理解多 ECharts 实例的尺寸调整问题

在 React 应用中集成 ECharts 图表时,为了确保图表能够适应不同屏幕尺寸或容器大小的变化,通常需要监听浏览器窗口的 resize 事件,并在事件触发时调用 ECharts 实例的 resize() 方法。然而,当页面中存在多个 ECharts 组件实例时,如果每个组件都尝试通过直接赋值 window.onresize 来注册其重绘逻辑,就会遇到一个常见问题:只有最后一个被渲染的 ECharts 图表能够响应窗口大小变化,而之前的图表则保持不变。

问题分析:window.onresize 的局限性

window.onresize 是一个 DOM 事件属性,它只能绑定一个事件处理函数。这意味着每当一个组件执行 window.onresize = function() { … } 时,它都会覆盖之前任何组件设置的 onresize 处理函数。因此,当页面中有多个 SimpleLine 组件实例时,它们会依次设置自己的 onresize 处理函数,最终只有最后一个组件的 onresize 会生效。

原始的 SimpleLine 组件中存在问题的代码片段如下:

useEffect(() => {  window.onresize = function () {      chartInstance2.resize();  };  return () => {      chartInstance2 && chartInstance2.dispose();  }; }, []);

这段代码在每次组件挂载时都会尝试重新赋值 window.onresize,导致了上述问题。

解决方案:使用 window.addEventListener

为了解决 window.onresize 的覆盖问题,我们应该使用 window.addEventListener 方法。addEventListener 允许为同一个事件类型注册多个事件处理函数,而不会互相覆盖。每个组件实例都可以独立地注册自己的 resize 事件处理函数,确保所有图表都能在窗口大小变化时正确重绘。

修改后的 useEffect 钩子应该如下所示:

useEffect(() => {  // 定义一个事件处理函数  const handleResize = () => {    chartInstance2 && chartInstance2.resize();  };  // 添加事件监听器  window.addEventListener("resize", handleResize);  // 组件卸载时清理 ECharts 实例并移除事件监听器  return () => {    window.removeEventListener("resize", handleResize);    chartInstance2 && chartInstance2.dispose();  };}, [chartInstance2]); // 确保当 chartInstance2 变化时重新注册监听器

在这个改进后的代码中:

我们定义了一个名为 handleResize 的函数来封装 chartInstance2.resize() 调用。window.addEventListener(“resize”, handleResize) 为当前组件实例添加了一个 resize 事件监听器。在 useEffect 的清理函数中,我们通过 window.removeEventListener(“resize”, handleResize) 移除了对应的事件监听器。这一步至关重要,它可以防止内存泄漏,并确保当组件卸载时,其事件处理函数不再被调用。将 chartInstance2 添加到 useEffect 的依赖数组中,以确保当图表实例本身发生变化时(尽管在这个例子中不太可能,但这是一个良好的实践),事件监听器能够被正确地重新注册。

完整的 ECharts 组件示例

结合上述修改,一个能够正确处理多个 ECharts 实例尺寸调整的 React 组件 SimpleLine.js 示例如下:

import React, { useRef, useEffect, useState } from "react";import * as echarts from "echarts";// 示例数据,实际应用中可能从 props 或 API 获取let xAxisDatas = [  "Jan 01", "Jan 02", "Jan 03", "Jan 04", "Jan 05", "Jan 06", "Jan 07", "Jan 08", "Jan 09", "Jan 10",  "Jan 11", "Jan 12", "Jan 13", "Jan 14", "Jan 15", "Jan 16", "Jan 17", "Jan 18", "Jan 19", "Jan 20",  "Jan 21", "Jan 22", "Jan 23", "Jan 24", "Jan 25", "Jan 26", "Jan 27", "Jan 28", "Jan 29", "Jan 30", "Jan 31",  // ... 更多数据];let data = [  {    name: 'A',    type: "line",    smooth: false,    showSymbol: true,    symbolSize: 0.1,    itemStyle: { color: '#0F4C5C' },    lineStyle: { width: 5 },    areaStyle: {      color: 'transparent',      opacity: 0.5,    },    label: {      show: true,      position: 'top',      color: "#0F4C5C",      fontSize: 15,      fontWeight: 'Bold',    },    data: [      31, 49, 36, 36, 30, 36, 36, 34, 38, 40, 34, 36, 32, 35, 34, 35, 32, 30, 37, 32, 40, 40, 33, 39,      31, 37, 34, 35, 38, 37, 33, 32, 38, 33, 35, 37, 37, 39, 33, 39, 45, 50, 51, 38, 39, 34, 32, 39,      31, 34, 31, 35, 34, 33, 30, 38, 38, 33, 68, 33, 35, 37, 32, 38, 30, 31, 30, 30, 31, 38, 39, 22,      32, 30, 35, 35, 37, 40, 31, 38, 34, 30, 36, 30, 34, 61, 31, 40, 40, 32, 35, 33, 39, 30, 34, 33,    ],    markLine: {      silent: true,      lineStyle: {        color: '#5d6664'      },      data: [{ yAxis: 38 }]    }  }];var option1 = {  textStyle: {    color: "#545454",    fontFamily: "Source Han Sans",    fontWeight: "lighter",    fontSize: '15',  },  tooltip: {    trigger: "axis",    axisPointer: {      type: "shadow",      crossStyle: {        color: "#999"      }    }  },  legend: {    data: ['A'],    left: "50%",    top: "2%",    itemWidth: 10,    itemHeight: 5  },  xAxis: {    type: "category",    data: xAxisDatas,    axisLabel: {      margin: "10"    },    name: "xAxisName",    nameLocation: "center",    nameGap: 30,    nameTextStyle: {      padding: [5, 0, 0, 0]    },    axisTick: {      alignWithLabel: true,      inside: true    }  },  yAxis: {    name: "",    type: "value",    splitLine: {      show: false    }  },  dataZoom: [    {      show: false,      realtime: true,      start: 50,      end: 100    },    {      type: "inside",      realtime: true,      start: 50,      end: 100    }  ],  grid: {    left: '2%',    top: '10%',    right: '2%',    bottom: '12%'  },  series: data,};function SimpleLine() {  const chartRef = useRef(null);  // 使用 useState 存储 chartInstance,确保其在组件生命周期内稳定  const [chartInstance, setChartInstance] = useState(null);  // 初始化图表实例  useEffect(() => {    if (chartRef.current) {      const renderedChartInstance = echarts.getInstanceByDom(chartRef.current);      let instance;      if (renderedChartInstance) {        instance = renderedChartInstance;      } else {        instance = echarts.init(chartRef.current);      }      instance.setOption(option1, true);      setChartInstance(instance); // 将实例保存到 state    }    // 组件卸载时清理 ECharts 实例(如果尚未通过 resize 监听器清理)    return () => {      // 这里的清理是备用,主要清理在 resize 监听器中进行      // chartInstance && chartInstance.dispose();    };  }, []); // 空依赖数组确保只在组件挂载时执行一次  // 监听窗口 resize 事件  useEffect(() => {    if (!chartInstance) return; // 确保 chartInstance 已经初始化    const handleResize = () => {      chartInstance.resize();    };    window.addEventListener("resize", handleResize);    return () => {      window.removeEventListener("resize", handleResize);      chartInstance.dispose(); // 在组件卸载时销毁 ECharts 实例    };  }, [chartInstance]); // 依赖 chartInstance,确保当它被设置后才注册监听器  return (    
);}export default SimpleLine;

注意事项与最佳实践

事件监听器的清理: 在 React 的 useEffect 钩子中,如果添加了事件监听器,务必在返回的清理函数中移除它 (removeEventListener)。这可以有效防止内存泄漏,尤其是在组件频繁挂载和卸载的场景中。

chartInstance 的管理: 将 ECharts 实例存储在 React 的 useState 或 useRef 中是推荐的做法。useState 更适用于需要在依赖项中使用的场景,而 useRef 则适用于不需要触发组件重新渲染的引用。在本例中,使用 useState 并将其作为 useEffect 的依赖项,可以确保当图表实例准备好后才注册 resize 监听器。

防抖 (Debounce) 或节流 (Throttle): 窗口 resize 事件在拖动窗口时会频繁触发。为了优化性能,避免 ECharts 图表过于频繁地重绘,可以考虑对 handleResize 函数进行防抖或节流处理。例如,使用 Lodash 库的 debounce 函数:

import { debounce } from 'lodash';// ...useEffect(() => {  if (!chartInstance) return;  const handleResize = () => {    chartInstance.resize();  };  // 使用 debounce 包装事件处理函数,例如每 100ms 触发一次  const debouncedHandleResize = debounce(handleResize, 100);  window.addEventListener("resize", debouncedHandleResize);  return () => {    window.removeEventListener("resize", debouncedHandleResize);    debouncedHandleResize.cancel(); // 取消任何待处理的防抖调用    chartInstance.dispose();  };}, [chartInstance]);

ResizeObserver (高级): 对于更复杂的布局或需要监听特定 DOM 元素尺寸变化的场景,可以考虑使用 ResizeObserver API。它允许您在元素的尺寸发生变化时得到通知,而不仅仅是窗口的尺寸变化。这在图表容器本身尺寸变化(而非窗口尺寸变化)时重绘图表非常有用。

通过采纳 window.addEventListener 和正确的 useEffect 清理机制,可以确保在 React 应用中渲染的多个 ECharts 图表都能够独立且正确地响应窗口大小变化,从而提供更稳定和响应式的用户体验。

以上就是React 中 ECharts 多实例窗口调整大小失效的解决方案的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1536036.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月21日 02:56:21
下一篇 2025年12月21日 02:56:40

相关推荐

  • 移动端rem计算导致页面扭曲变动如何解决?

    解决移动端rem计算导致页面扭曲变动的问题 在移动端项目中使用rem作为根节点字体大小的计算方式时,可能会遇到页面首次打开时出现css扭曲变动的现象。这是因为根节点字体大小赋值后,会导致页面内容重绘。 解决方法: 将计算根节点字体大小的js代码移动到页面的最开头,放置在 标签内。 原理: 这样做可以…

    2025年12月24日
    200
  • Nuxt 移动端项目中 rem 计算导致 CSS 变形,如何解决?

    Nuxt 移动端项目中解决 rem 计算导致 CSS 变形 在 Nuxt 移动端项目中使用 rem 计算根节点字体大小时,可能会遇到一个问题:页面内容在字体大小发生变化时会重绘,导致 CSS 变形。 解决方案: 可将计算根节点字体大小的 JS 代码块置于页面最前端的 标签内,确保在其他资源加载之前执…

    2025年12月24日
    200
  • Nuxt 移动端项目使用 rem 计算字体大小导致页面变形,如何解决?

    rem 计算导致移动端页面变形的解决方法 在 nuxt 移动端项目中使用 rem 计算根节点字体大小时,页面会发生内容重绘,导致页面打开时出现样式变形。如何避免这种现象? 解决方案: 移动根节点字体大小计算代码到页面顶部,即 head 中。 原理: flexível.js 也遇到了类似问题,它的解决…

    2025年12月24日
    000
  • 如何避免使用rem计算造成页面变形?

    避免rem计算造成页面变形 在使用rem计算根节点字体大小时,可能会遇到页面在第一次打开时出现css扭曲变动的现象。这是因为在浏览器运行到计算根节点字体大小的代码时,页面内容已经开始展示,随后根节点字体大小的赋值操作会导致页面内容重绘,从而产生变形效果。 要避免这种情况,可以在页面的最前面,也就是h…

    2025年12月24日
    000
  • 网页布局中,使用 translate 转换元素位置的优势有哪些?

    为什么考虑使用 translate 而非定位属性更改元素位置 在网页布局中,我们通常使用元素的定位属性(如 left、right、top、bottom)来控制元素在文档流中的位置。然而,在某些情况下,我们可能考虑使用 translate 转换来改变元素位置。 使用 translate 的优势: 不会…

    2025年12月24日
    000
  • 为什么使用 `translate` 比修改定位改变元素位置更有效?

    为什么使用 translate 而不是修改定位来改变元素位置? 在某些情况下,使用 translate 而不是修改元素的定位来改变其位置更具优势。 原因如下: 减少重绘和重排:改变 transform 不会触发重排或重绘,只会触发复合。而修改元素定位可能会触发重排,代价更高。动画更平滑:使用 tra…

    2025年12月24日
    000
  • 浮动元素修改宽高,是否会触发布局调整?

    浮动元素自有其渲染之法,修改宽高影响布局否? 浮动元素的存在使文本内容对其环绕,倘若对其宽高频繁修改,是否会触发大规模的布局调整? 让我们从分层与渲染视角着手,进一步探究问题的答案。 从分层来看,浮动元素与其相邻元素处于同一层级。而从渲染角度观察,图像的绘制(paint)可被称作重绘,布局(layo…

    2025年12月24日
    000
  • 修改浮动元素宽高会触发重排吗?

    修改浮动元素宽高后是否会触发重排 众所周知,浮动元素会影响与其相邻文本内容的位置。那么,如果对一个浮动元素反复修改其宽高,会否引发大规模重排呢? 根据浏览器的分层机制和渲染流程,浮动元素与其相邻元素位于同一层。在分层渲染中,”paint”对应重绘,”layout&…

    2025年12月24日
    200
  • 反复修改浮动元素宽高会触发重排吗?

    修改浮动元素宽高对重排的影响 众所周知,当浮动元素出现时,相邻文本内容会环绕其排列。那么,反复修改浮动元素的宽高是否会触发重排呢? 影响布局,重排是必然 从渲染模型的角度来看,修改浮动元素的宽高将影响其布局,因为这改变了元素在文档流中的位置。具体来说,浮动元素的宽高修改将触发布局重排(layout)…

    2025年12月24日
    000
  • 修改浮动图片元素的宽高会触发重排吗?

    对浮动元素修改宽高的操作是否会触发重排 众所周知,设置浮动属性的图片元素会使相邻文本内容在其周围环绕。那么,如果对这样的图片元素反复修改宽高,是否会出现大规模的重排呢?答案是肯定的。 原因如下: 布局层级影响 从布局层级来看,浮动的图片元素与相邻文本内容处于同一层级。当修改图片元素的宽高时,相邻文本…

    2025年12月24日
    400
  • css怎么用现代布局

    CSS 现代布局利用弹性盒布局和网格布局系统,提供了灵活、响应且模块化的方式来组织网页元素,轻松适应不同屏幕尺寸和设备。弹性盒布局适合创建单向布局,例如导航栏,而网格布局适用于设计复杂布局,如仪表板。使用弹性盒布局和网格布局时,可通过简单易用的 CSS 属性,控制元素尺寸、对齐方式和排列方向,实现响…

    2025年12月24日
    000
  • CSS中contain属性的语法是怎样的

    CSS中contain属性用于指定一个元素是否应该包含或被包含在其他元素内部。通过设置contain属性,可以告诉浏览器哪些元素应该被独立处理,从而提高页面的渲染性能。 contain属性的语法如下: contain: layout [paint] [size] [style] layout:表示元…

    2025年12月24日
    000
  • 粘性定位的标准及粘性定位的要素和要求分析

    粘性定位是一种常见的网页布局技术,通过使元素在滚动时保持固定位置,提供更好的用户体验。本文将解析粘性定位的标准、要素和要求,并提供具体代码示例。 一、粘性定位的标准 兼容性:粘性定位应在主流浏览器上正常工作,如Chrome、Firefox、Safari等。滚动效果:元素在滚动时应平滑过渡,避免出现闪…

    2025年12月24日 好文分享
    000
  • 分析回流和重绘:探讨二者的差异和功能

    回流与重绘:解析二者的区别与作用 在前端开发中,优化网页性能常常是一个重要的任务。而回流(reflow)和重绘(repaint)是影响网页性能的两个关键因素。本文将详细解析回流与重绘的区别,并探讨它们在优化网页性能中的作用。 回流与重绘的区别回流和重绘都是指浏览器渲染页面时的操作,但它们的区别在于操…

    2025年12月24日
    000
  • 提高网页加载速度的最佳方法:优化重绘和回流

    最佳实践:优化重绘和回流,提升网页加载速度 在如今移动设备和高速互联网的时代,网页的加载速度直接影响着用户体验和网站的流量。过慢的加载速度不仅会让用户流失,还会降低用户满意度,从而影响网页排名和转化率。因此,对于网页开发者来说,优化网页加载速度是一个很重要的任务。其中,优化重绘和回流是提升网页加载速…

    2025年12月24日
    000
  • 探究回流与重绘的异同及适用领域

    深入探讨回流与重绘:差异和应用场景,需要具体代码示例 前言: 在前端开发中,回流(reflow)和重绘(repaint)是常见的概念。它们与页面渲染密切相关,对性能优化至关重要。本文将深入探讨回流和重绘的差异以及它们的应用场景,并给出具体的代码示例。 一、回流(reflow)是什么? 回流指的是浏览…

    2025年12月24日
    000
  • 优化CSS解析过程中的回流和重绘技巧

    CSS回流和重绘解析及优化技巧 近年来,网页性能优化成为了前端开发中的重要环节,其中包括对CSS回流和重绘的解析及优化。在优化CSS的过程中,我们需要了解回流和重绘的定义,并学习一些具体的优化技巧。 什么是回流和重绘? 回流(reflow)和重绘(repaint)是浏览器渲染引擎对网页进行布局和绘制…

    2025年12月24日
    000
  • 最佳性能优化:前端开发者必须了解的避免重绘和回流策略

    极致性能优化:前端开发者应该知道的重绘和回流规避策略,需要具体代码示例 引言:在现代Web开发中,性能优化一直是前端开发者需要关注的重要问题之一。其中,重绘和回流是造成性能问题的两个关键因素。本文将介绍什么是重绘和回流,并提供一些规避策略和具体代码示例,以帮助前端开发者在日常工作中更好地优化性能。 …

    2025年12月24日
    000
  • 揭秘CSS回流与重绘的原理

    解密CSS回流和重绘的工作原理 引言:在网页开发过程中,我们经常会听到CSS回流(reflow)和重绘(repaint)这两个概念。理解它们的工作原理对于优化网页性能和提高用户体验至关重要。本文将深入探讨CSS回流和重绘的工作原理,并提供具体的代码示例,帮助读者更好地理解这两个概念。 一、CSS回流…

    2025年12月24日
    000
  • 提高网页性能:减少重绘和回流的技巧

    优化网页性能:重绘和回流的避免技巧 随着移动设备的普及和网页内容的不断增加,用户对于网页性能的要求也越来越高。在优化网页性能的过程中,我们经常会遇到两个非常重要的概念,即重绘(Repaint)和回流(Reflow)。这两个概念对于网页性能的影响非常大,正确地避免或减少重绘和回流,能够显著提升网页的加…

    2025年12月24日
    000

发表回复

登录后才能评论
关注微信