一、问题

使用vue3写页面,引入一个echarts图,父组件数据改变,图表没有重新渲染。

二、目标效果图

在这里插入图片描述

三、解决(数据变了, 图表不变化)

只需要2步:

1、echarts图组件监听数据(数据改变,重新渲染)

watch(
		() => props.chartData,
		() => {
			//dispose为了解决警告 There is a chart instance already initialized on the dom.
			echart.dispose(document.getElementById('LineBar'))
			initChart() //重新渲染的方法
		},{deep: true}
	)

2、在使用setOption()方法之前,重新给option中的数据赋值即可,代码如下:

let initChart = () => {
		let Echarts = echarts.init(document.getElementById('LineBar'))
		 //重新赋值(必须,否则渲染不上)
		option.value.xAxis.data = props.chartData.xAxisData
		option.value.series[0].data = props.chartData.data
		// 绘制图表
		Echarts.setOption(option.value)
		// 自适应大小
		window.addEventListener(
			'resize',
			(window.onresize = () => {
				Echarts.resize()
			})
		)
	}

注意:父组件正常调接口 传值即可

解决警告 There is a chart instance already initialized on the dom.

echart.dispose(document.getElementById('LineBar'))

解决警告Instance ec_1680155339347 has been disposed

不要使用以下写法:(暂时不清楚具体原因)


window.addEventListener(
		'resize',
		(window.onresize = () => {
			Echarts.resize()
		})
		)

改为这样写法:

window.addEventListener('resize', onResize(Echarts))
let onResize = (Echarts) => {
		window.onresize = () => {
			Echarts.resize()
		}
	}

四、Echarts子组件 完整代码

<template>
	<div id="LineBar"></div>
</template>
<script name="LineBar" setup>
	import { onMounted, defineProps, watch } from 'vue'
	import * as echarts from 'echarts'

	const props = defineProps({
		chartData: {
			type: Object,
			required: true
		}
	})
	watch(
		() => props.chartData,
		() => {
			//解决警告 There is a chart instance already initialized on the dom.
			echart.dispose(document.getElementById('LineBar'))
			initChart()
		},
		{deep: true}
	)
	let option = ref({
		tooltip: {
			trigger: 'axis'
		},
		// legend: {
		// 	data: vulnerabilityTrendData.value.xdata
		// },
		grid: {
			left: '3%',
			right: '4%',
			bottom: '3%',
			containLabel: true
		},
		xAxis: {
			type: 'category',
			boundaryGap: false,
			data: props.chartData.xAxisData
		},
		yAxis: {
			type: 'value'
		},
		series: [
			{
				name: 'ddd',
				type: 'line',
				smooth: true,
				data: props.chartData.data,
				areaStyle: {
					color: {
						type: 'linear',
						x: 0,
						y: 0,
						x2: 0,
						y2: 1,
						colorStops: [
							{
								offset: 0,
								color: 'rgba(46, 121, 255, 0.2)' // 0% 处的颜色
							},
							{
								offset: 1,
								color: 'rgba(46, 121, 255, 0.0001)' // 100% 处的颜色
							}
						]
					}
				},
				color: '#2E79FF',
				lineStyle: {
					color: {
						colorStops: [
							{
								offset: 0,
								color: '#8477FF'
							},
							{
								offset: 1,
								color: '#5CCAFF'
							}
						]
					},
					width: 2,
					shadowOffsetY: 12,
					shadowColor: 'rgba(59, 138, 254, 0.1)'
				}
			}
		]
	})
	let echart = echarts

	onMounted(() => {
		initChart()
	})
	let initChart = () => {
		let Echarts = echarts.init(document.getElementById('LineBar'))
		//手动赋值
		option.value.xAxis.data = props.chartData.xAxisData
		option.value.series[0].data = props.chartData.data
		// 绘制图表
		Echarts.setOption(option.value)
		// 自适应大小(这样写会出现:父组件数据修改,浏览器窗口大小改变,会警告Instance ec_1680155339347 has been disposed)
		//window.addEventListener(
		//	'resize',
		//	(window.onresize = () => {
		//		Echarts.resize()
		//	})
		//)
		//改成以下写法
		window.addEventListener('resize', onResize(Echarts))
	}
	let onResize = (Echarts) => {
		window.onresize = () => {
			Echarts.resize()
		}
	}
</script>

<style scoped></style>

解决方法二

options不设置为变量,设置为函数

const options = () => {
  const { xData, yData } = { ...props.chartData };
  return {
    tooltip: {
      trigger: 'axis',
      axisPointer: {
        type: 'shadow',
      },
    },
    color: ['#4874CB', '#ED812F'],
    legend: {
      y: 'bottom',
    },
    title: {
      text: '成本使用情况',
      left: 'center',
    },
    grid: {
      left: '3%',
      right: '4%',
      bottom: '10%',
      containLabel: true,
    },
    xAxis: {
      type: 'value',
    },
    yAxis: {
      type: 'category',
      data: xData,
    },
    series: [
      {
        name: '花费成本',
        type: 'bar',
        stack: 'total',
        label: {
          show: true,
        },
        emphasis: {
          focus: 'series',
        },
        data: yData[0],
      },
      {
        name: '剩余成本',
        type: 'bar',
        stack: 'total',
        label: {
          show: true,
        },
        emphasis: {
          focus: 'series',
        },
        data: yData[1],
      },
    ],
  };
};

使用时

function onInit() {
  if (isEmpty(chartDom.value)) {
    chartDom.value = proxy.$echarts.init(proxy.$refs[CHART_REF]);
  }
  chartDom.value.setOption(options(), true); // 第二个参数为true,可以防止有残留的连线
}
onMounted(() => onInit());
// watch(() => props.chartFlag, () => { //设置这个参数,在父组件数据变化时,设置chartFlag=!chartFlag
 // onInit();
//});
// 否则需要设置深度
watch(() => props.chartData, () => {
 onInit();
}, {
  deep: true,
   });
Logo

Vue社区为您提供最前沿的新闻资讯和知识内容

更多推荐