Vue 3 开发中的 ECharts 5 使用

Posted by Yun on Mon, Jan 31, 2022

随着 Vue 更新到了 V3 版本,ECharts 更新到了 V5 版本,它们均新增加了对 TypeScript 非常友好的支持。鉴于现有的开发方式与原先 Vue V2 版本仍然具有一些区别,所以本文在此给出一个新版的开发样例。

1. 示例代码

本节以标准柱形图为例,使用 Composition API 以及 TypeScript 进行代码编写。

TestChart.vue

 1<template>
 2  <div ref="chartRef" style="width: 100%; height: 400px"></div>
 3</template>
 4
 5<script lang="ts">
 6import { defineComponent, onBeforeUnmount, onMounted, ref } from "vue";
 7import * as echarts from "echarts/core";
 8import { BarChart } from "echarts/charts";
 9import {
10  TooltipComponent,
11  GridComponent,
12  DataZoomComponent,
13} from "echarts/components";
14import { LabelLayout } from "echarts/features";
15import { CanvasRenderer } from "echarts/renderers";
16import { useChartData } from "./useChart";
17
18export default defineComponent({
19  name: "TestChart",
20  setup() {
21    const chartRef = ref<HTMLDivElement>();
22    let chart: echarts.ECharts | null = null;
23    echarts.use([
24      BarChart,
25      TooltipComponent,
26      GridComponent,
27      DataZoomComponent,
28      LabelLayout,
29      CanvasRenderer,
30    ]);
31
32    const { initOption } = useChartData();
33
34    const resizeHandler = () => {
35      chart?.resize();
36    };
37
38    onMounted(() => {
39      chart = echarts.init(chartRef.value as HTMLDivElement);
40      chart.setOption(initOption);
41
42      window.addEventListener("resize", resizeHandler);
43    });
44
45    onBeforeUnmount(() => {
46      window.removeEventListener("resize", resizeHandler);
47      chart?.dispose();
48    });
49
50    return {
51      chartRef,
52    };
53  },
54});
55</script>

当然,也可以使用 script setup 版本的代码:

TestChart.vue script setup:

 1<template>
 2  <div ref="chartRef" style="width: 100%; height: 400px"></div>
 3</template>
 4
 5<script setup lang="ts">
 6import { onBeforeUnmount, onMounted, ref } from "vue";
 7import * as echarts from "echarts/core";
 8import { BarChart } from "echarts/charts";
 9import {
10  TooltipComponent,
11  GridComponent,
12  DataZoomComponent,
13} from "echarts/components";
14import { LabelLayout } from "echarts/features";
15import { CanvasRenderer } from "echarts/renderers";
16import { useChartData } from "./useChart";
17
18const chartRef = ref<HTMLDivElement>();
19let chart: echarts.ECharts | null = null;
20echarts.use([
21  BarChart,
22  TooltipComponent,
23  GridComponent,
24  DataZoomComponent,
25  LabelLayout,
26  CanvasRenderer,
27]);
28
29const { initOption } = useChartData();
30
31const resizeHandler = () => {
32  chart?.resize();
33};
34
35onMounted(() => {
36  chart = echarts.init(chartRef.value as HTMLDivElement);
37  chart.setOption(initOption);
38
39  window.addEventListener("resize", resizeHandler);
40});
41
42onBeforeUnmount(() => {
43  window.removeEventListener("resize", resizeHandler);
44  chart?.dispose();
45});
46</script>

useChart.ts

 1import * as echarts from "echarts/core";
 2import { BarSeriesOption } from "echarts/charts";
 3import {
 4  TooltipComponentOption,
 5  GridComponentOption,
 6  DataZoomComponentOption,
 7} from "echarts/components";
 8
 9export type ECOption = echarts.ComposeOption<
10  | BarSeriesOption
11  | TooltipComponentOption
12  | GridComponentOption
13  | DataZoomComponentOption
14>;
15
16export function useChartData(): {
17  initOption: ECOption;
18} {
19  const initOption: ECOption = {
20    tooltip: {
21      trigger: "axis",
22      axisPointer: {
23        type: "shadow",
24      },
25    },
26    xAxis: [
27      {
28        type: "category",
29        data: ["A", "B", "C", "D", "E"],
30        axisTick: {
31          alignWithLabel: true,
32        },
33      },
34    ],
35    yAxis: [
36      {
37        type: "value",
38      },
39    ],
40    dataZoom: [
41      {
42        type: "inside",
43        orient: "horizontal",
44      },
45      {
46        type: "slider",
47        orient: "horizontal",
48        start: 0,
49        end: 100,
50      },
51    ],
52    series: [
53      {
54        type: "bar",
55        data: [123, 332, 22, 1, 23],
56        label: {
57          show: true,
58          position: "top",
59        },
60        itemStyle: {
61          color: "#27727B",
62        },
63        labelLayout: {
64          hideOverlap: true,
65        },
66        emphasis: {
67          label: {
68            show: true,
69            fontWeight: "bolder",
70            fontSize: 15,
71          },
72          itemStyle: {
73            shadowColor: "rgba(0, 0, 0, 0.7)",
74            shadowBlur: 10,
75          },
76        },
77      },
78    ],
79  };
80
81  return {
82    initOption,
83  };
84}

参考链接:

2. 关于控制台报错 `resize` should not be called during main process

一般情况下,对 ECharts 图表封装并不需要将 echarts 对象暴露到渲染上下文中。如果确实有意将 echarts 对象声明为响应式,请使用 shallowRef 而非 ref

1// GOOD
2const chart = shallowRef<echarts.ECharts>(); 
3
4// BAD
5const chart = ref<echarts.ECharts>();

如果不使用 shallowRef,可能会导致命令行报错 `resize` should not be called during main process;事实上,任何第三方库创造的实例都应当使用 shallowRef 而非 ref 进行响应式处理。

参考链接:


版权声明:本文遵循 CC BY-SA 4.0 版权协议,转载请附上原文出处链接和本声明。

Copyright statement: This article follows the CC BY-SA 4.0 copyright agreement. For reprinting, please attach the original source link and this statement.