Vue3 零基础每日笔记(080):Vue3 + ECharts 数据可视化——封装可复用图表组件

一、前言

后台系统绕不开图表:销量趋势、占比分布、实时监控。本篇用 Vue3 + ECharts 干两件事:按需引入省体积 (077 篇精神)+ 封装 BaseChart 通用组件(一次封装全项目用,resize 自动跟随)。

bash 复制代码
npm install echarts

二、按需引入:全量 1MB → 按需 300KB

ECharts 全量引入很简单但体积感人;生产用 echarts/core 手动注册需要的模块:

ts 复制代码
// src/plugins/echarts.ts ------ 统一注册处
import * as echarts from 'echarts/core'
import { BarChart, LineChart, PieChart } from 'echarts/charts'        // 图表类型
import {
  GridComponent,      // 网格(柱状/折线必配)
  TooltipComponent,   // 提示框
  LegendComponent,    // 图例
  TitleComponent      // 标题
} from 'echarts/components'
import { CanvasRenderer } from 'echarts/renderers'                    // 渲染器

echarts.use([
  BarChart, LineChart, PieChart,
  GridComponent, TooltipComponent, LegendComponent, TitleComponent,
  CanvasRenderer
])

export default echarts

用到新图表类型(如 MapChart)时回来加一行注册------忘了注册报"Unknown series xxx",先想到这里查。

三、封装 BaseChart 组件

设计目标:父组件只传 option(配置对象),组件负责 init / 更新 / resize / 销毁:

vue 复制代码
<!-- src/components/BaseChart.vue -->
<template>
  <div ref="chartRef" :style="{ width: '100%', height: height }"></div>
</template>

<script setup lang="ts">
import { ref, watch, onMounted, onBeforeUnmount } from 'vue'
import { useResizeObserver } from '@vueuse/core'        // 079 篇
import echarts from '@/plugins/echarts'
import type { EChartsOption } from 'echarts'

const props = withDefaults(
  defineProps<{
    option: EChartsOption      // 图表配置:数据变了图表自动更新
    height?: string
  }>(),
  { height: '320px' }          // ★ 默认高度,容器必须有高度才能渲染
)

const chartRef = ref<HTMLDivElement>()
let chart: echarts.ECharts | null = null   // ★ 非响应式:echarts 实例不需要响应式包裹

onMounted(() => {
  chart = echarts.init(chartRef.value!)
  chart.setOption(props.option)
})

// ★ option 变化 → 更新(notMerge 彻底替换,防止旧系列残留)
watch(
  () => props.option,
  (newOption) => chart?.setOption(newOption, true),
  { deep: true }
)

// ★ 容器尺寸变化 → 自适应(080 篇最高频需求)
useResizeObserver(chartRef, () => chart?.resize())

// ★ 销毁实例,防内存泄漏
onBeforeUnmount(() => {
  chart?.dispose()
  chart = null
})
</script>

四个职责对应四个生命周期动作:挂载 init → 数据 watch setOption → 尺寸 resize → 卸载 dispose。

四、完整可运行代码:使用方

vue 复制代码
<!-- src/views/ChartView.vue -->
<template>
  <el-row :gutter="12">
    <el-col :span="12">
      <BaseChart :option="barOption" height="300px" />
    </el-col>
    <el-col :span="12">
      <BaseChart :option="lineOption" height="300px" />
    </el-col>
  </el-row>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import BaseChart from '@/components/BaseChart.vue'
import type { EChartsOption } from 'echarts'

// 柱状图:商品销量
const barOption = ref<EChartsOption>({
  title: { text: '商品销量 TOP5' },
  tooltip: { trigger: 'axis' },
  xAxis: { type: 'category', data: ['键盘', '鼠标', '耳机', '显示器', '主机'] },
  yAxis: { type: 'value' },
  series: [{ type: 'bar', data: [320, 280, 210, 180, 120], itemStyle: { color: '#7c3aed' } }]
})

// 折线图:模拟接口返回后更新
const lineOption = ref<EChartsOption>({
  title: { text: '访问趋势' },
  tooltip: { trigger: 'axis' },
  xAxis: { type: 'category', data: ['周一', '周二', '周三', '周四', '周五'] },
  yAxis: { type: 'value' },
  series: [{ type: 'line', data: [150, 230, 224, 218, 135], smooth: true }]
})

// 模拟:2 秒后接口数据到了,折线图自动更新(watch 生效验证)
setTimeout(() => {
  lineOption.value = {
    ...lineOption.value,
    series: [{ type: 'line', data: [90, 110, 160, 240, 300], smooth: true }]
  }
}, 2000)
</script>

【截图位置:左右两个图表;2 秒后折线图数据自动刷新】

注意 option 里已包含 title 配置,组件不额外接收 title prop------图表外观全由 option 决定。

五、option 配置从哪来

不需要背配置!三步法:

text 复制代码
1. 去 echarts 官网 Examples 挑一个长得像的
2. 复制 option 粘到 BaseChart 的 prop 里
3. 改数据、改颜色(itemStyle.color、颜色数组 color 数组)

主题色联动(071 篇):把品牌色抽成常量,ECharts 配置和 CSS 变量用同一份------全站颜色统一。

六、踩坑记录

  1. 图表不显示、无报错:容器高度为 0(div 默认高度 0)------显式给 height(组件默认 320px 兜底)
  2. 数据变了图不变 :直接改 option 内部属性但引用没变,或 watch 没开 deep------统一走 watch(() => props.option, ..., { deep: true })
  3. 切换类型后旧数据残留 :setOption 默认合并模式------第二个参数传 true(notMerge 完全替换)
  4. 窗口拉伸图表不跟:没监听 resize------useResizeObserver 兜底(比 window resize 精准到容器)
  5. tab 切换回来图表空白:组件在 display:none 时 init,宽高算出来是 0------切换可见后再 init 或手动 resize
  6. echarts 实例包进 ref :ref(echarts.init(...)) 被代理后内部对象行为异常------实例用普通变量存,别做响应式
  7. Unknown series type: xxx:按需引入漏注册图表类型------去 plugins/echarts.ts 补注册

七、今日小结

  • 按需引入:echarts/core + use(...) 注册图表/组件/渲染器,忘了注册就 Unknown series
  • BaseChart 四职责:init / setOption(notMerge)/ resize(ResizeObserver)/ dispose
  • 实例不做响应式 ;容器必须有高度
  • 配置不用背:官网 Examples 抄 + 改数据改色

下篇预告

内容编辑绕不开富文本:公告、文章、商品详情。下一篇 081 富文本编辑器集成 wangEditor 5:Vue3 封装、图片上传配置,以及必踩的销毁坑。

相关推荐
阿狗童鞋1 小时前
前端工程化实战指南
前端
CappuccinoRose1 小时前
CSS 动效基础
前端·css·动画·animation·transition
用户4402818278071 小时前
我用 TRAE 一晚上从零撸了个微信投票小程序: 17 个云函数 + 11 个页面的全链路实战
前端
BullSmall1 小时前
SonarQube 9.9.8-community 适配 Jenkins 版本说明
java·前端·jenkins
tryCbest1 小时前
第一篇:HTML5 核心知识全解 + 项目起步
前端·html·html5
沪上企服通1 小时前
从票据采集到凭证生成:代账 pipeline 的 OCR、查重与规则引擎设计笔记
笔记·ocr
百度一下吧1 小时前
CSS 伪类使用与实践:从入门到进阶
前端·css
hunterandroid1 小时前
android方案 : Multiplatform 跨平台开发实战:一套代码,多端运行
android·前端