做後台系統或營運大屏的前端工程師,大概都有過這種時刻:後端丟來一張幾千行的報表,老闆盯著密密麻麻的數字皺眉頭,你卻在想——同樣的數據,如果能變成一根會說話的柱子、一條會拐彎的曲線,溝通成本起碼少一半。數據可視化不是把圖畫漂亮這麼簡單,它是把「人腦難以處理的資訊」翻譯成「人眼一眼就懂的語言」。這篇文章延續「從 X 開始」實戰指南系列,帶你用 ECharts 在 Vue 3 專案裡,從零把數據變成能上牆的圖表大屏。
一、為什麼前端工程師也要懂可視化
很多團隊把圖表當成「順手加一下」的附屬品,結果做出來的圖要麼卡頓、要麼和設計稿對不上。其實可視化有三個容易被忽略的價值:
- 降維打擊:時間序列、分布、佔比,圖表一眼勝過千行表格。
- 異常顯性化:告警數據用紅綠熱力圖,誰都能秒懂哪裡出問題。
- 決策加速器:大屏讓管理者在 3 秒內抓住重點,而不是翻 10 頁報表。
對做威脅情報、資產監控這類「數據即戰場」的系統,可視化幾乎是剛需。
二、ECharts 是什麼:一張圖表背後的引擎
ECharts 是百度開源、現由 Apache 基金會維護的視覺化庫,基於 Canvas/WebGL 渲染,支援折線、柱狀、散點、地圖、關係圖等幾十種圖表。它的核心心智模型很簡單:你只要描述「數據長什麼樣」和「想要什麼樣式」,剩下的渲染交給它。比起手刻 SVG,ECharts 在大數據量、動畫、自適應上都省下大量功夫。
三、步驟 1:在 Vue 3 專案中安裝與引入
先安裝依賴(以 Vite + Vue 3 為例):
npm install echarts
為了避免全量引入導致打包體積膨脹,重點:在 Vite 這類建置工具下,建議用按需引入(echarts/core + 具體圖表/元件),只註冊你用到的模組:
// echarts.ts
import * as echarts from 'echarts/core';
import { BarChart, LineChart } from 'echarts/charts';
import {
TitleComponent,
TooltipComponent,
GridComponent,
LegendComponent,
} from 'echarts/components';
import { CanvasRenderer } from 'echarts/renderers';
echarts.use([
BarChart,
LineChart,
TitleComponent,
TooltipComponent,
GridComponent,
LegendComponent,
CanvasRenderer,
]);
export default echarts;
四、步驟 2:封裝一個可複用的圖表組件
圖表組件的重點是「掛載時初始化、數據變化時 setOption、卸載時 dispose」,否則會記憶體洩漏:
<template>
<div ref="chartRef" :style="{ width: '100%', height: height }"></div>
</template>
<script setup lang="ts">
import { onMounted, onBeforeUnmount, ref, watch } from 'vue';
import echarts from '@/utils/echarts';
const props = defineProps<{
option: Record<string, unknown>;
height?: string;
}>();
const chartRef = ref<HTMLDivElement>();
let chart: echarts.ECharts | null = null;
onMounted(() => {
if (!chartRef.value) return;
chart = echarts.init(chartRef.value);
chart.setOption(props.option);
});
watch(
() => props.option,
(opt) => chart && chart.setOption(opt, true),
{ deep: true },
);
onBeforeUnmount(() => {
chart?.dispose();
chart = null;
});
</script>
五、步驟 3:接 API 動態渲染與自適應
實戰中數據幾乎都來自介面。用 useTable 或 fetch 拿到資料後,組成 ECharts 的 option 物件即可:
import { ref, onMounted, onBeforeUnmount } from 'vue';
const option = ref({});
const dailyCounts = ref<{ date: string; count: number }[]>([]);
async function loadData() {
const res = await fetch('/api/log/daily-counts');
dailyCounts.value = await res.json();
option.value = {
tooltip: { trigger: 'axis' },
xAxis: { type: 'category', data: dailyCounts.value.map((d) => d.date) },
yAxis: { type: 'value' },
series: [
{ type: 'bar', data: dailyCounts.value.map((d) => d.count), itemStyle: { color: '#22d3ee' } },
],
};
}
// 重點:容器尺寸變化時必須呼叫 resize,否則圖表會被壓扁或留白
let ro: ResizeObserver | null = null;
onMounted(() => {
loadData();
const el = chartRef.value!;
ro = new ResizeObserver(() => chart?.resize());
ro.observe(el);
});
onBeforeUnmount(() => ro?.disconnect());
六、步驟 4:打造大屏的幾個實戰技巧
大屏和一般報表不同,它要「遠看有氣勢、近看有細節」:
- 深色毛玻璃底:用半透明卡片 + 青色邊框,讓圖表像浮在控制檯上。
- 呼吸脈衝動畫:對告警類指標用
animationDuration+ 陰影脈衝,引導視線。 - 統一調色板:全站定義一套主色,避免圖表各畫各的。
- 地圖疊加:威脅來源這類地理數據,用 ECharts 的 geo/map 系列直接上「3D 地球」或平面世界地圖。
七、常見坑與效能注意
特別注意:大數據量(上萬點)時,優先用 dataset + appendData 或開啟 large: true 的散點模式,必要時切到 WebGL 渲染器;同時每個圖表實例都要 dispose,切頁不釋放就會記憶體堆積。另外,option 頻繁更新時用 setOption(opt, true) 而非合併,能避免舊系列殘留。
數據可視化是一道「技術 + 設計 + 業務理解」的複合題。把上面的組件封裝好、把自適應與釋放做紮實,你就能在半天內搭出一面讓老闆點頭的大屏。
互動話題:你在專案裡最頭痛的圖表場景是什麼?是大數據量卡頓、還是設計稿還原度不夠?留言告訴我,我們一起拆。