在大屏可视化项目中,我们常常需要用到很多的图表组件,通常你会编写很多的option对图表进行渲染,以及引入它们所需的一些组件并使用echart.use。
在Vue2中我们常常把可复用的组件单独抽离出来,再通过props、emit等方法向复用组件中传入组件所需数据,而在Vue3中我们可以将一些逻辑功能写成hook进行抽离和复用再传入到视图中,这会不仅让你的组件中的代码更加优雅而且阅读性更强。
{#_label1}
封装思路 {#heading-1}
{#_lab2_1_0}
引入模块 {#heading-2}
我们先创建lib.ts文件,用于将echart图表中所需要用到组件全部引入进来并导出。
由于引入的模块过多,所以我们把它引入的模块的代码抽离出来,增加代码的可阅读性
// lib.ts
import * as echarts from 'echarts/core';
import {
BarChart,
LineChart,
PieChart,
MapChart,
PictorialBarChart,
RadarChart,
ScatterChart
} from 'echarts/charts';
import {
TitleComponent,
TooltipComponent,
GridComponent,
PolarComponent,
AriaComponent,
ParallelComponent,
LegendComponent,
RadarComponent,
ToolboxComponent,
DataZoomComponent,
VisualMapComponent,
TimelineComponent,
CalendarComponent,
GraphicComponent
} from 'echarts/components';
echarts.use([
LegendComponent,
TitleComponent,
TooltipComponent,
GridComponent,
PolarComponent,
AriaComponent,
ParallelComponent,
BarChart,
LineChart,
PieChart,
MapChart,
RadarChart,
PictorialBarChart,
RadarComponent,
ToolboxComponent,
DataZoomComponent,
VisualMapComponent,
TimelineComponent,
CalendarComponent,
GraphicComponent,
ScatterChart
]);
export default echarts;
封装功能 {#heading-3}
在同级目录下创建一个useChart.ts文件,这是我们复用echart图表hook文件。
封装功能如下:
-
监听图表元素变化及视图,自动重新渲染图表适应高度
-
可传入主题、渲染模式(SVG、Canvas)
-
loading效果
import { nextTick, onMounted, onUnmounted, Ref, unref } from "vue";
import type { EChartsOption } from 'echarts';
import echarts from "./lib";
import { SVGRenderer, CanvasRenderer } from "echarts/renderers";
import { RenderType, ThemeType } from "./types";
export default function useChart(elRef: Ref<HTMLDivElement>, autoChartSize = false, animation: boolean = false, render: RenderType = RenderType.SVGRenderer, theme: ThemeType = ThemeType.Default) {
// 渲染模式
echarts.use(render === RenderType.SVGRenderer ? SVGRenderer : CanvasRenderer)
// echart实例
let chartInstance: echarts.ECharts | null = null;
// 初始化echart
const initCharts = () => {
const el = unref(elRef)
if (!el || !unref(el)) {
return
}
chartInstance = echarts.init(el, theme);
}
// 更新/设置配置
const setOption = (option: EChartsOption) => {
nextTick(() => {
if (!chartInstance) {
initCharts();
if (!chartInstance) return;
}
chartInstance.setOption(option)
hideLoading()
})
}
// 获取echart实例
function getInstance(): echarts.ECharts | null {
if (!chartInstance) {
initCharts();
}
return chartInstance;
}
// 更新大小
function resize() {
chartInstance?.resize();
}
// 监听元素大小
function watchEl() {
// 给元素添加过渡
if (animation) { elRef.value.style.transition = 'width 1s, height 1s' }
const resizeObserver = new ResizeObserver((entries => resize()))
resizeObserver.observe(elRef.value);
}
// 显示加载状
function showLoading() {
if (!chartInstance) {
initCharts();
}
chartInstance?.showLoading()
}
// 显示加载状
function hideLoading() {
if (!chartInstance) {
initCharts();
}
chartInstance?.hideLoading()
}
onMounted(() => {
window.addEventListener('resize', resize)
if (autoChartSize) watchEl();
})
onUnmounted(() => {
window.removeEventListener('resize', resize)
})
return {
setOption,
getInstance,
showLoading,
hideLoading
}
}
// types.ts
export enum RenderType {
SVGRenderer = 'SVGRenderer',
CanvasRenderer = 'SVGRenderer'
}
export enum ThemeType {
Light = 'light',
Dark = 'dark',
Default = 'default'
}
有了以上封装好之后的代码,我们在组件中使用echart图表库时将会更加简单而高效。
{#_lab2_1_2}
使用例子 {#heading-4}
// index.vue
<template>
<div ref="chartEl" :style="{ width: `300px`, height: `300px` }"></div>
</template>
<script setup>
import { onMounted, Ref, ref, computed, nextTick } from "vue";
import type { EChartsOption } from 'echarts'
import useChart, { RenderType, ThemeType } from '../../useChart'
import axios from 'axios'
const option = computed<EChartsOption>(() => ({
// ...chart option
}))
const chartEl = ref<HTMLDivElement | null>(null)
const {
setOption,
showLoading
} = useChart(chartEl as Ref<HTMLDivElement>, true, true, RenderType.SVGRenderer, ThemeType.Dark)
onMounted(() => {
nextTick(() => {
// 显示loading
showLoading()
// 假装有网络请求 ...
// 渲染图表
setOption(option.value);
})
})
</script>
大家试试吧!