vue3,echarts图表刷新空白,或者说父组件代码改动图表就空白问题

需要考虑和排查:

  1. 数据更新问题

    • 父组件更新数据时,确保数据传递给子组件的 对象发生了变化。在 Vue 中,响应式数据更新需要通过赋值新对象或修改对象属性来触发。如果只是修改对象的属性值而不修改对象本身,可能不会触发子组件的重新渲染。
    • 在打印输出中,确保 打印的数据确实反映了父组件更新后的数据状态,包括 值。
  2. 图表初始化和销毁

    • 确保在子组件中正确地初始化和销毁 echarts 实例。每次父组件数据更新时,应当先销毁之前的 echarts 实例,然后重新初始化新的实例并渲染新的图表。
    • 在 Vue 生命周期的 onMounted 钩子中初始化图表,在 onUnmounted 钩子中销毁图表实例,确保不会出现资源泄漏或重复渲染的问题。
  3. 图表容器元素问题

    • 确保图表的容器元素 #main 在子组件挂载时已经正确渲染到页面上,并且是可见的。
    • 使用 document.getElementById('main') 获取图表容器时,确保该元素可以被正确找到并且存在于 DOM 树中。
  4. 异步数据加载

    • 如果父组件数据是通过异步获取的,例如通过接口请求获取数据,需要确保在数据完全获取并且传递给子组件之后再进行图表的渲染和更新操作。
  5. 调试和排查

    • 在子组件中增加更多的调试信息,例如打印数据和控制台日志,以便确认数据的传递和图表的渲染过程。
    • 使用浏览器的开发者工具检查控制台输出、DOM 结构和样式,以确定是否存在错误或异常情况。
  6. 图表容器设置:

    • 确保图表容器(<div id="main"></div>)已经正确渲染到页面上,并且能够通过 document.getElementById('main') 获取到。

两种解决方案①用ref代替id引入图表容器-这里我是父组件获取传过来的

<template>
子组件
  <PageWrapper dense fixedHeight contentFullHeight>
    <h6 class="h6">{{ infoecharts.title }}</h6>
    <div class="top-chart">
      <!-- 使用 ref 来引用图表容器 -->
      <div ref="chartContainer" class="chart-container"></div>
    </div>
  </PageWrapper>
</template>

<script lang="ts" setup>
 import { defineProps, watch, onMounted, onUnmounted, ref, nextTick } from 'vue';
  import echarts, { ECharts } from '/@/utils/lib/echarts';

  interface InfoEcharts {
    title: string;
    xAxisData: string[];
    data2: number[];
  }

  const props = defineProps<{
    infoecharts: InfoEcharts;
  }>();

  let chartInstance: ECharts | null = null;
  const chartContainer = ref<HTMLElement | null>(null);

  const showChart = () => {
    if (!chartContainer.value) {
      console.error('Chart container element not found');
      return;
    }

    if (!chartInstance) {
      chartInstance = echarts.init(chartContainer.value);
    }

    const { xAxisData, data2 } = props.infoecharts;
    const data1 = data2.map((value) => Math.abs(value));

    const option = {
      xAxis: {
        type: 'category',
        data: xAxisData,
      },
      yAxis: {
        type: 'value',
        show: false,
      },
      series: [
        {
          data: data1,
          type: 'bar',
          label: {
            show: true,
            position: 'top',
            formatter: (params: any) => {
              const value = data2[params.dataIndex];
              return value;
              // return value > 0 ? `+${value}` : `${value}`;
            },
          },
          barWidth: 120,
          barGap: '50%',
        },
      ],
    };

    try {
      chartInstance.setOption(option);
      // console.log('Chart option set successfully');
    } catch (error) {
      // console.error('Failed to set chart option:', error);
    }

    // Listen for window resize events to resize the chart
    window.addEventListener('resize', () => {
      chartInstance?.resize();
    });
  };

  watch(
    () => props.infoecharts,
    () => {
      nextTick(() => {
        showChart();
      });
    },
    { immediate: true, deep: true },
  );

  onMounted(() => {
    showChart();
  });

  onUnmounted(() => {
    if (chartInstance) {
      chartInstance.dispose();
      chartInstance = null;
      console.log('Chart disposed');
    }
  });
</script>
<style lang="less" scoped>
  .h6 {
    position: absolute;
    left: 5px;
  }

  .top-chart {
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: center;

    .chart-container {
      height: 320px;
      width: 100%; /* Use percentage width for responsiveness */
    }
  }
</style>

解决方案还是用id引入,②用定时器延迟一下保证数据拿到了再应用注册图表

<template>
  <PageWrapper dense fixedHeight contentFullHeight>
    <!-- <h6 class="h6">报表</h6> -->
    <div v-for="n in uses" :key="n.id">
      <div class="top-chart" :id="`main-${n.id}`"></div>
      <hr />
    </div>
  </PageWrapper>
</template>

<script lang="ts" setup>
  import { onMounted, onUnmounted, ref, reactive } from 'vue';
  import echarts from '/@/utils/lib/echarts';
  const uses = reactive([{ name: '盘点', id: 11 }]);
  const generateRandomChartData = () => {
    return [
      { value: Math.floor(Math.random() * 1000), name: '张三' },
      { value: Math.floor(Math.random() * 1000), name: '李四' },
    ].map((item) => ({
      value: item.value,
      name: `${item.name}: ${((item.value / 1000) * 100).toFixed(2)}%`,
    }));
  };

  const generateRandomChartData1 = () => {
    return [
      { value: Math.floor(Math.random() * 1000), name: '导表' },
      { value: Math.floor(Math.random() * 1000), name: '手机录入' },
      { value: Math.floor(Math.random() * 1000), name: '手持机感应' },
    ].map((item) => ({
      value: item.value,
      name: `${item.name}: ${((item.value / 1000) * 100).toFixed(2)}%`,
    }));
  };
  // fetchData();
  function fetchData() {
    setTimeout(() => {
      const uses = reactive([{ name: '盘点', id: 11 }]);
      const generateRandomChartData = () => {
        return [
          { value: Math.floor(Math.random() * 1000), name: '张三1' },
          { value: Math.floor(Math.random() * 1000), name: '李四' },
        ].map((item) => ({
          value: item.value,
          name: `${item.name}: ${((item.value / 1000) * 100).toFixed(2)}%`,
        }));
      };

      const generateRandomChartData1 = () => {
        return [
          { value: Math.floor(Math.random() * 1000), name: '导表' },
          { value: Math.floor(Math.random() * 1000), name: '手机录入' },
          { value: Math.floor(Math.random() * 1000), name: '手持机感应' },
        ].map((item) => ({
          value: item.value,
          name: `${item.name}: ${((item.value / 1000) * 100).toFixed(2)}%`,
        }));
      };
      uses.forEach((item) => {
        showChart(`main-${item.id}`, item.name);
      });
    }, 100);
  }
  const showChart = (chartId: string, title: string) => {
    const chartDom = document.getElementById(chartId);
    if (chartDom) {
      const myChart = echarts.init(chartDom);
      const option = {
        title: [
          {
            subtext: '完成人员占比',
            left: '24.67%',
            top: '85%',
            textAlign: 'center',
          },
          {
            subtext: '盘点方式占比',
            left: '74.33%',
            top: '85%',
            textAlign: 'center',
          },
        ],
        tooltip: {
          trigger: 'item',
        },
        series: [
          {
            type: 'pie',
            radius: '40%',
            center: ['25%', '50%'],
            data: generateRandomChartData(),
            label: {
              position: 'outer',
              alignTo: 'none',
              bleedMargin: 5,
            },
          },
          {
            type: 'pie',
            radius: '40%',
            center: ['75%', '50%'],
            data: generateRandomChartData1(),
            label: {
              position: 'outer',
              alignTo: 'none',
              bleedMargin: 5,
            },
          },
        ],
      };
      myChart.setOption(option);

      // 监听窗口大小变化,重新渲染图表
      window.addEventListener('resize', () => {
        myChart.resize();
      });

      // 在组件销毁时销毁图表
      onUnmounted(() => {
        myChart.dispose();
      });
    }
  };

  onMounted(() => {
    fetchData();
  });
</script>

<style scoped>
  .top-chart {
    display: flex;
    align-items: center;
    justify-content: space-around;
    height: 400px; /* 调整图表容器高度 */
  }
</style>

还是不行请参考后者前辈的方案:

echarts在vue3中的使用——其他页面跳转回echarts图表页面时,不显示图表的问题_echarts在页面不显示-CSDN博客

路由切换再回来Echart图表消失问题_echarts切换页面图表消失的原因-CSDN博客

  • 15
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值