前言
封装一个通用的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>