前言
封装一个通用的Echart 我们可以从以下几点出发:
- 支持动态数据:接收外部传递的配置和数据,自动更新图表。
- 多种图表类型:允许通过配置项切换不同类型的图表(如折线图、柱状图等)。
- 组件生命周期管理:自动初始化、更新和销毁 ECharts 实例,防止内存泄漏。
- 方法暴露:通过
ref
暴露组件方法(如手动更新、导出图表)。
封装子组件
<template>
<!-- 图表容器 -->
<div ref="chartRef" style="width: 100%; height: 100%;"></div>
</template>
<script setup>
import { ref, watch, onMounted, onBeforeUnmount, defineExpose } from 'vue';
import * as echarts from 'echarts';
// Props
defineProps({
option: {
type: Object,
required: true,
},
autoResize: {
type: Boolean,
default: true,
},
});
// Refs
const chartRef = ref(null); // 图表容器 DOM
let chartInstance = null; // 图表实例
// 初始化图表
const initChart = () => {
if (!chartRef.value) return;
// 销毁旧的实例,避免重复初始化
if (chartInstance) {
chartInstance.dispose();
}
// 创建新的 ECharts 实例
chartInstance = echarts.init(chartRef.value);
// 设置初始配置
if (props.option) {
chartInstance.setOption(props.option);
}
};
// 更新图表配置
const updateChart = (newOption) => {
if (chartInstance) {
chartInstance.setOption(newOption, true); // true 表示合并更新
}
};
// 调整图表大小
const resizeChart = () => {
if (chartInstance) {
chartInstance.resize();
}
};
// 动态监听配置项变化
watch(
() => props.option,
(newOption) => {
updateChart(newOption);
},
{ deep: true }
);
// 组件挂载时初始化
onMounted(() => {
initChart();
if (props.autoResize) {
// 监听窗口大小变化
window.addEventListener('resize', resizeChart);
}
});
// 组件卸载时销毁实例
onBeforeUnmount(() => {
if (chartInstance) {
chartInstance.dispose();
chartInstance = null;
}
if (props.autoResize) {
window.removeEventListener('resize', resizeChart);
}
});
// 暴露方法给父组件
defineExpose({
resizeChart, // 手动调整尺寸
updateChart, // 手动更新图表
getChartInstance: () => chartInstance, // 获取图表实例
});
</script>
<style scoped>
/* 图表容器必须有固定宽高 */
div {
width: 100%;
height: 400px;
}
</style>
使用子组件
使用 ref
引用子组件实例,动态调用暴露的方法:
resizeChart
:调整尺寸。updateChart
:手动更新图表配置。getChartInstance
:获取实例对象,进行导出或事件绑定等高级操作。
一般实战开发,图表的option
我们会单独封装一个文件,option
的配置一般比较长,影响开发浏览体验。这里只做示例,放在一块。
<template>
<div>
<!-- 动态数据更新 -->
<EChartsWrapper ref="chartComponent" :option="chartOption" />
<!-- 操作按钮 -->
<button @click="updateData">更新数据</button>
<button @click="resizeChart">调整尺寸</button>
<button @click="exportChart">导出图表</button>
</div>
</template>
<script setup>
import { ref } from 'vue';
import EChartsWrapper from './EChartsWrapper.vue';
// 图表配置
const chartOption = ref({
title: {
text: '动态图表',
},
tooltip: {
trigger: 'axis',
},
xAxis: {
type: 'category',
data: ['1月', '2月', '3月', '4月', '5月'],
},
yAxis: {
type: 'value',
},
series: [
{
name: '销量',
type: 'bar',
data: [120, 200, 150, 80, 70],
},
],
});
// 引用 EChartsWrapper 实例
const chartComponent = ref(null);
// 更新数据
const updateData = () => {
const newData = chartOption.value.series[0].data.map(() => Math.floor(Math.random() * 300));
chartOption.value.series[0].data = newData; // 动态更新数据
};
// 手动调整尺寸
const resizeChart = () => {
chartComponent.value.resizeChart(); // 调用子组件暴露的方法
};
// 导出图表为图片
const exportChart = () => {
const instance = chartComponent.value.getChartInstance();
const imgURL = instance.getDataURL({
type: 'png',
pixelRatio: 2,
});
const a = document.createElement('a');
a.href = imgURL;
a.download = 'chart.png';
a.click();
};
</script>