vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > Vue3优化使用ECharts

在Vue3项目中优化使用ECharts的完整方案

作者:Pu_Nine_9

在Vue3项目中使用 ECharts,如何做到按需打包、类型安全、响应式适配、自动销毁?本文分享一套可直接落地的封装方案,需要的朋友可以参考下

一、整体思路

二、文件 1:@/utils/echarts/index.ts—— 按需引入并导出

// TODO: 二次封装 ECharts 实例
import * as echarts from 'echarts/core'

// 引入使用的图表
import {
  BarChart,
  LineChart,
  PieChart
} from 'echarts/charts'

// 系列组件
import {
  TitleComponent,
  TooltipComponent,
  GridComponent,
  LegendComponent,
  VisualMapComponent,
  GeoComponent
} from 'echarts/components'

// 功能增强模块
import {
  LabelLayout,
  UniversalTransition
} from 'echarts/features'

// 渲染器
import { CanvasRenderer } from 'echarts/renderers'

// 注册所有必须组件
echarts.use([
  // 图表
  BarChart,
  LineChart,
  PieChart,
  // 组件
  TitleComponent,
  TooltipComponent,
  GridComponent,
  LegendComponent,
  VisualMapComponent,
  GeoComponent,
  // 功能
  LabelLayout,
  UniversalTransition,
  // 渲染
  CanvasRenderer
])

// 导出类型
export * from '../../types'   // 这里指向你自己的全局类型文件,也可以直接导出 echarts 自带类型

// 导出手动封装后的 echarts
export { echarts }

说明:如果你的项目没有单独的 ../../types,可以直接改为导出 ECharts 的官方类型:

export type { ECharts, EChartsOption } from 'echarts'

三、文件 2:@/utils/echarts/types.ts—— 统一的 EChartsOption 类型(可选)

/**
 * 从 echarts/core 导入 ComposeOption 和 ECharts 类型
 * ComposeOption 是 ECharts 提供的类型组合工具,用于创建包含多种组件和图表类型的配置选项类型
 * ECharts 是 ECharts 实例的类型
 */
import type { ComposeOption } from 'echarts/core'

/**
 * 从 echarts/charts 导入图表系列类型
 */
import type {
  BarSeriesOption,
  LineSeriesOption,
  PieSeriesOption
} from 'echarts/charts'

/**
 * 从 echarts/components 导入组件配置类型
 */
import type {
  TitleComponentOption,
  TooltipComponentOption,
  LegendComponentOption,
  GridComponentOption,
  VisualMapComponentOption,
  GeoComponentOption
} from 'echarts/components'

/**
 * 导出具体的图表类型,方便在需要时单独使用
 */
export type { ECharts } from 'echarts/core'
export type {
  BarSeriesOption,
  LineSeriesOption,
  PieSeriesOption
} from 'echarts/charts'

/**
 * 统一的 EChartsOption 类型
 * 使用 ComposeOption 组合所有需要的类型,创建一个完整的配置选项类型
 * 这样可以获得更好的类型提示和类型检查
 */
export type EChartsOption = ComposeOption<
  | BarSeriesOption
  | LineSeriesOption
  | PieSeriesOption
  | TitleComponentOption
  | TooltipComponentOption
  | LegendComponentOption
  | GridComponentOption
  | VisualMapComponentOption
  | GeoComponentOption
>

说明:如果你的项目没有单独的类型文件,也可以直接使用 ECharts 官方导出的 EChartsOption,但上述手动组合可以精确控制可用组件,避免类型提示中出现未注册的组件。

四、文件 3:@/hooks/useECharts.ts—— 核心 Hook

import { ref, watch, onMounted, onUnmounted, unref, type Ref } from 'vue'
import { echarts } from '@/utils/echarts'
import type { EChartsOption, ECharts } from '@/utils/echarts'

/**
 * ECharts 图表 Hook
 * 自动初始化、响应式更新配置、自动销毁、窗口自适应
 *
 * @param elRef - 图表挂载的 DOM 引用(可以是 Ref 或原生 DOM 元素)
 * @param option - 图表配置项
 * @param autoResize - 是否自动跟随窗口大小变化,默认 true
 * @returns { chart, updateOption }
 */
export const useECharts = (
  elRef: Ref<HTMLElement | null> | HTMLElement | null | undefined,
  option: EChartsOption,
  autoResize = true
) => {
  const chart = ref<ECharts | null>(null)

  // 初始化图表
  const initChart = () => {
    const dom = unref(elRef)
    if (!dom) return
    chart.value = echarts.init(dom)
    chart.value.setOption(option)
  }

  // 更新配置
  const updateOption = (newOption: EChartsOption) => {
    chart.value?.setOption(newOption)
  }

  // 监听配置变化
  watch(
    () => option,
    () => updateOption(option),
    { deep: true }
  )

  // 监听 DOM 元素变化
  let resizeObserver: ResizeObserver | null = null
  const resize = () => chart.value?.resize()

  watch(
    () => unref(elRef),
    (newEl) => {
      if (newEl) {
        initChart()
        if (autoResize) {
          resizeObserver?.disconnect()
          resizeObserver = new ResizeObserver(resize)
          resizeObserver.observe(newEl)
        }
      }
    },
    { immediate: true }
  )

  // 组件挂载
  onMounted(() => {
    initChart()
    if (autoResize) {
      window.addEventListener('resize', resize)
      const dom = unref(elRef)
      if (dom) {
        resizeObserver = new ResizeObserver(resize)
        resizeObserver.observe(dom)
      }
    }
  })

  // 组件卸载
  onUnmounted(() => {
    if (autoResize) {
      window.removeEventListener('resize', resize)
      resizeObserver?.disconnect()
    }
    chart.value?.dispose()
    chart.value = null
  })

  return {
    chart: chart.value,
    updateOption,
  }
}

五、使用示例

5.1 基础用法

<template>
  <div ref="chartRef" style="width: 100%; height: 400px" />
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { useECharts } from '@/hooks/useECharts'
import type { EChartsOption } from '@/utils/echarts'

const chartRef = ref<HTMLElement>()

const option: EChartsOption = {
  title: { text: '月度销售趋势' },
  tooltip: {},
  xAxis: { type: 'category', data: ['1月', '2月', '3月', '4月'] },
  yAxis: { type: 'value' },
  series: [{ type: 'line', data: [120, 200, 150, 80] }]
}

const { chart, updateOption } = useECharts(chartRef, option, true)

// 模拟动态更新数据
setTimeout(() => {
  updateOption({
    series: [{ type: 'line', data: [300, 400, 250, 100] }]
  })
}, 3000)
</script>

5.2 响应式 option 自动更新

如果你的 option 是响应式数据(比如从 API 获取),且希望数据变化时图表自动更新,可以直接传入一个 refcomputed

<script setup>
import { ref } from 'vue'

const chartData = ref([120, 200, 150])
const option = computed(() => ({
  xAxis: { data: ['A', 'B', 'C'] },
  series: [{ type: 'bar', data: chartData.value }]
}))

const { chart } = useECharts(chartRef, option.value)
// 现在当 chartData 变化时,option 会重新计算,并触发 watch 自动调用 updateOption
</script>

5.3 手动控制 resize

如果某些场景下不需要自动 resize(比如弹窗中的图表),可以将第三个参数设为 false,然后手动调用 updateOption 中的 resize 逻辑(需要扩展 hook)。

六、方案优缺点总结

优点

待改进点(可根据项目需求继续完善)

你可以在此基础上按需扩展,例如:

// 增加事件监听
const on = (event: string, handler: any) => chart.value?.on(event, handler)
// 增加 loading
const showLoading = () => chart.value?.showLoading()
const hideLoading = () => chart.value?.hideLoading()

七、结语

这套封装已经在多个中大型 Vue 3 项目中实践,兼顾了灵活性、性能和开发体验。如果你正为 ECharts 集成发愁,不妨直接复制以上三个文件到你的项目中,再根据实际需求微调。

以上就是在Vue3项目中优化使用ECharts的完整方案的详细内容,更多关于Vue3优化使用ECharts的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文