Vue3 useEcharts 封装

107 min read

查看echarts 定义的类型

export { install$49 as AriaComponent, AriaOption as AriaComponentOption, install$33 as AxisPointerComponent, AxisPointerOption as AxisPointerComponentOption, install$34 as BrushComponent, BrushOption as BrushComponentOption, install$29 as CalendarComponent, CalendarOption as CalendarComponentOption, install$43 as DataZoomComponent, DataZoomComponentOption, install$44 as DataZoomInsideComponent, install$45 as DataZoomSliderComponent, install$51 as DatasetComponent, DatasetOption as DatasetComponentOption, install$26 as GeoComponent, GeoOption as GeoComponentOption, install$30 as GraphicComponent, GraphicComponentLooseOption as GraphicComponentOption, install$23 as GridComponent, GridOption as GridComponentOption, install$22 as GridSimpleComponent, install$40 as LegendComponent, LegendComponentOption, install$42 as LegendPlainComponent, install$41 as LegendScrollComponent, install$39 as MarkAreaComponent, MarkAreaOption as MarkAreaComponentOption, install$38 as MarkLineComponent, MarkLineOption as MarkLineComponentOption, install$37 as MarkPointComponent, MarkPointOption as MarkPointComponentOption, install$28 as ParallelComponent, ParallelCoordinateSystemOption as ParallelComponentOption, install$24 as PolarComponent, PolarOption as PolarComponentOption, install$25 as RadarComponent, RadarOption as RadarComponentOption, install$27 as SingleAxisComponent, SingleAxisOption as SingleAxisComponentOption, install$36 as TimelineComponent, TimelineOption as TimelineComponentOption, install$35 as TitleComponent, TitleOption as TitleComponentOption, install$31 as ToolboxComponent, ToolboxComponentOption, install$32 as TooltipComponent, TooltipOption as TooltipComponentOption, install$50 as TransformComponent, install$46 as VisualMapComponent, VisualMapComponentOption, install$47 as VisualMapContinuousComponent, install$48 as VisualMapPiecewiseComponent } from './shared';

定义全局类型

global.d.ts

/* eslint-disable @typescript-eslint/no-unused-vars */
export global {
  type AnyFunction<T=any> = (...args: any[]) => T
  type Recordable<T = any> = Record<string, T>
}

按需导入echarts类型

import * as echarts from 'echarts/core'

import {
  BarChart,
  GaugeChart,
  LineChart,
  MapChart,
  PictorialBarChart,
  PieChart,
  RadarChart,
} from 'echarts/charts'

import {
  AriaComponent,
  CalendarComponent,
  DataZoomComponent,
  GridComponent,
  LegendComponent,
  ParallelComponent,
  PolarComponent,
  RadarComponent,
  TimelineComponent,
  TitleComponent,
  ToolboxComponent,
  TooltipComponent,
  VisualMapComponent,
} from 'echarts/components'

import { CanvasRenderer } from 'echarts/renderers'

echarts.use([
  LegendComponent,
  TitleComponent,
  TooltipComponent,
  GridComponent,
  PolarComponent,
  AriaComponent,
  ParallelComponent,
  BarChart,
  LineChart,
  PieChart,
  MapChart,
  RadarChart,
  GaugeChart,
  CanvasRenderer,
  PictorialBarChart,
  RadarComponent,
  ToolboxComponent,
  DataZoomComponent,
  VisualMapComponent,
  TimelineComponent,
  CalendarComponent,
])

export default echarts

useEcharts

import { tryOnUnmounted, useBreakpoints, useDebounceFn, useEventListener, useTimeoutFn } from '@vueuse/core'
import echarts from './lib/echarts'

import type { EChartsOption } from 'echarts'
import type { Ref } from 'Vue'

export function useECharts(
  elRef: Ref<HTMLDivElement>,
  theme: 'light' | 'dark' | 'default' = 'light',
) {
  let chartInstance: echarts.ECharts | null = null
  let resizeFn: AnyFunction<void> = resize
  const cacheOptions = ref<EChartsOption>({})
  let removeResizeFn: AnyFunction<void> = () => {}

  resizeFn = useDebounceFn(resize, 200)

  const getOptions = computed((): EChartsOption => {
    return {
      backgroundColor: 'transparent',
      ...cacheOptions.value,
    } as EChartsOption
  })

  function initCharts(t = theme) {
    const el = unref(elRef)
    if (!el || !unref(el))
      return

    chartInstance = echarts.init(el, t)
    removeResizeFn = useEventListener(window, 'resize', resizeFn)
    const breakpoints = useBreakpoints({
      xs: 480,
      sm: 576,
      md: 768,
      lg: 992,
      xl: 1200,
      xxl: 1400,
    })
    if (breakpoints.isSmaller('md') || el.offsetHeight === 0) {
      useTimeoutFn(() => {
        resizeFn()
      }, 30)
    }
  }

  async function setOptions(options: EChartsOption, clear = true) {
    cacheOptions.value = options
    if (unref(elRef)?.offsetHeight === 0) {
      useTimeoutFn(() => {
        setOptions(unref(getOptions))
      }, 30)
      return
    }
    await nextTick(() => {
      useTimeoutFn(() => {
        if (!chartInstance) {
          initCharts('default')

          if (!chartInstance)
            return
        }
        clear && chartInstance?.clear()

        chartInstance?.setOption(unref(getOptions))
      }, 30)
    })
  }

  function resize() {
    chartInstance?.resize()
  }

  tryOnUnmounted(() => {
    if (!chartInstance)
      return
    removeResizeFn()
    chartInstance.dispose()
    chartInstance = null
  })

  function getInstance(): echarts.ECharts | null {
    if (!chartInstance)
      initCharts('default')

    return chartInstance
  }

  return {
    setOptions,
    resize,
    echarts,
    getInstance,
  }
}