为了方便在不同页面使用 echarts,可以封装一个组件。如果不封装,也可以手动实例化 echarts,并且额外处理监听容器尺寸变化的功能。
html
<script setup lang="ts">
import { useResizeObserver } from "@vueuse/core";
import type { EChartsOption } from "echarts";
import { init, type ECharts, type ECElementEvent } from "echarts/core";
const props = defineProps<{
/** Echarts 图表配置选项 */
options?: EChartsOption;
/** 图表渲染器类型,默认为 svg */
renderer?: "canvas" | "svg";
}>();
const emit = defineEmits<{
chartClick: [event: ECElementEvent];
}>();
/** 图表容器元素的引用 */
const container = useTemplateRef("figure-element");
/** Echarts 图表实例 */
const chart = shallowRef<ECharts>();
defineExpose({
container,
chart,
});
/**
* 监听图表配置变化并更新图表
*/
watchEffect(() => {
if (!chart.value || !props.options) return;
chart.value.setOption(props.options);
});
/**
* 监听容器尺寸变化并自动调整图表大小
*/
useResizeObserver(container, () => {
if (!chart.value || chart.value.isDisposed()) return;
chart.value.resize();
});
/**
* 初始化图表实例
*/
watch(container, (container) => {
if (!container) return;
const instance = init(container, undefined, {
renderer: props.renderer || "svg",
locale: "ZH",
});
/** 绑定图表点击事件 */
instance.on("click", (event) => {
emit("chartClick", event);
});
chart.value = instance;
onWatcherCleanup(() => instance.dispose());
});
</script>
<template>
<figure ref="figure-element" :class="$style.figure" />
</template>
<style module>
.figure {
overflow: hidden;
}
</style>
然后在页面中使用。
html
<script setup lang="ts">
import type { EChartsOption } from "echarts";
import { BarChart, LineChart, PieChart, ScatterChart } from "echarts/charts";
import {
GridComponent,
LegendComponent,
TitleComponent,
TooltipComponent,
} from "echarts/components";
import { use } from "echarts/core";
import { UniversalTransition } from "echarts/features";
import { SVGRenderer } from "echarts/renderers";
import EchartsContainer from "@/components/Echarts/EchartsContainer.vue";
use([
GridComponent,
LineChart,
BarChart,
SVGRenderer,
PieChart,
ScatterChart,
UniversalTransition,
TitleComponent,
TooltipComponent,
LegendComponent,
]);
/** 基础柱状图配置 */
const barChartOption: EChartsOption = {
tooltip: {
trigger: "axis",
axisPointer: {
type: "shadow",
},
},
xAxis: {
type: "category",
data: ["一月", "二月", "三月", "四月", "五月", "六月"],
axisTick: {
alignWithLabel: true,
},
},
yAxis: {
type: "value",
},
series: [
{
name: "销售额",
type: "bar",
data: [120, 200, 150, 80, 70, 110],
},
],
};
/** 折线图配置 */
const lineChartOption: EChartsOption = {
tooltip: {
trigger: "axis",
},
legend: {
data: ["新用户", "活跃用户"],
},
xAxis: {
type: "category",
data: ["周一", "周二", "周三", "周四", "周五", "周六", "周日"],
},
yAxis: {
type: "value",
},
series: [
{
name: "新用户",
type: "line",
data: [120, 132, 101, 134, 90, 230, 210],
smooth: true,
itemStyle: {
color: "#67C23A",
},
},
{
name: "活跃用户",
type: "line",
data: [220, 182, 191, 234, 290, 330, 310],
smooth: true,
itemStyle: {
color: "#E6A23C",
},
},
],
};
/** 饼图配置 */
const pieChartOption: EChartsOption = {
tooltip: {
trigger: "item",
formatter: "{a} <br/>{b}: {c} ({d}%)",
},
legend: {
orient: "vertical",
left: "left",
},
series: [
{
name: "产品分类",
type: "pie",
radius: "50%",
data: [
{ value: 1048, name: "电子产品" },
{ value: 735, name: "服装配饰" },
{ value: 580, name: "家居用品" },
{ value: 484, name: "食品饮料" },
{ value: 300, name: "其他" },
],
},
],
};
/** 散点图配置 */
const scatterChartOption: EChartsOption = {
tooltip: {
trigger: "item",
},
xAxis: {
type: "value",
name: "X轴",
},
yAxis: {
type: "value",
name: "Y轴",
},
series: [
{
name: "数据点",
type: "scatter",
data: Array.from({ length: 50 }, () => [Math.random() * 100, Math.random() * 100]),
},
],
};
/** 处理图表点击事件 */
const handleChartClick = (chartType: string) => {
ElMessage.info(`点击了${chartType}图表`);
};
</script>
<template>
<div :class="$style.container">
<!-- 柱状图 -->
<EchartsContainer
:class="$style.chart"
:options="barChartOption"
@chart-click="handleChartClick('柱状图')"
/>
<!-- 折线图 -->
<EchartsContainer
:class="$style.chart"
:options="lineChartOption"
@chart-click="handleChartClick('折线图')"
/>
<!-- 饼图 -->
<EchartsContainer
:class="$style.chart"
:options="pieChartOption"
@chart-click="handleChartClick('饼图')"
/>
<!-- 散点图 -->
<EchartsContainer
:class="$style.chart"
:options="scatterChartOption"
@chart-click="handleChartClick('散点图')"
/>
</div>
</template>
<style module>
.container {
padding: 2rem;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
}
.chart {
height: 30rem;
}
</style>