从0到1用Echarts做数据可视化 折线图柱状图饼图实战教程含Vue集成与常见问题排查
说实话,我第一次接触Echarts的时候也是懵的。文档写得挺全,但真正上手的时候还是踩了不少坑。今天我想和你聊聊怎么从零开始用Echarts做出漂亮的数据可视化,顺便把Vue集成的姿势和那些让人抓狂的bug一起解决掉。
先认识一下这位”老朋友”
Echarts是百度开源的一个用JavaScript实现的开源可视化库,底层依赖ZRender。说人话就是:你在浏览器里画图表,它帮你把那些复杂的canvas操作都封装好了。现在已经是Apache的顶级项目了,社区活跃度非常高,文档也是中文的,对国内开发者特别友好。
支持图表类型大概有二十多种,常用的折线图、柱状图、饼图、散点图、雷达图它都能画。而且它有个好处——响应式很好,适配各种屏幕,做大屏展示的时候特别香。
环境准备:把Echarts请进门
首先你得有个项目。如果你还没准备好,可以随便找个空文件夹初始化一下:
mkdir my-chart-project
cd my-chart-project
npm init -y
然后安装Echarts,直接:
npm install echarts --save
如果你想用Vue项目,可以用Vite快速搭建:
npm create vite@latest vue-echarts-demo -- --template vue
cd vue-echarts-demo
npm install echarts --save
npm install vue-echarts
这里提一下vue-echarts这个包。它是官方维护的Vue组件封装,用起来比原生的echarts.init方便很多,尤其适合已经用Vue的同学。当然如果你偏原生,后面我也会讲怎么在Vue里直接调用Echarts。
第一个折线图:从”Hello World”开始
咱们先从最简单的折线图练手。创建一个HTML文件,或者直接在Vue组件里写,核心代码是这样的:
import * as echarts from 'echarts';
// 拿到DOM元素
const chartDom = document.getElementById('line-chart');
// 初始化实例
const myChart = echarts.init(chartDom);
// 准备数据
const option = {
title: {
text: '近七天销售额趋势',
left: 'center'
},
tooltip: {
trigger: 'axis'
},
legend: {
data: ['销售额', '成本']
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
},
yAxis: {
type: 'value'
},
series: [
{
name: '销售额',
type: 'line',
smooth: true, // 平滑曲线
data: [120, 132, 101, 134, 90, 230, 210],
areaStyle: {
opacity: 0.3 // 填充区域
}
},
{
name: '成本',
type: 'line',
smooth: true,
data: [80, 90, 70, 95, 60, 180, 160],
itemStyle: {
color: '#ff7f50'
}
}
]
};
// 设置配置项
myChart.setOption(option);
// 窗口变化时自适应
window.addEventListener('resize', () => {
myChart.resize();
});
这里有一个新手容易踩的坑:smooth: true 会让折线变得圆滑,但如果你数据量很大,可能会卡顿。这时候可以关掉平滑,或者改用line类型配合step来实现阶梯线。另外containLabel: true这个属性也很重要,它会让图表的网格区域自动包含坐标轴标签,避免标签被截断。
柱状图:对比数据的不二选择
柱状图在展示分类数据对比时特别好用。比如说你要比较不同产品的销量,柱状图就比折线图直观多了。
const barOption = {
title: {
text: '各产品月度销量对比',
left: 'center'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow' // 鼠标悬停时显示阴影指示器
}
},
legend: {
data: ['2023年', '2024年']
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
data: ['产品A', '产品B', '产品C', '产品D', '产品E']
},
yAxis: {
type: 'value',
name: '销量(件)'
},
series: [
{
name: '2023年',
type: 'bar',
data: [320, 302, 341, 374, 390],
itemStyle: {
color: '#5470c6'
}
},
{
name: '2024年',
type: 'bar',
data: [420, 432, 491, 434, 490],
itemStyle: {
color: '#91cc75'
}
}
]
};
柱状图还有一些进阶玩法。比如说你要做堆叠柱状图,只需要在series里加上stack: 'total'属性:
series: [
{
name: '线上渠道',
type: 'bar',
stack: 'total', // 堆叠的关键
data: [320, 302, 341, 374, 390]
},
{
name: '线下渠道',
type: 'bar',
stack: 'total',
data: [120, 132, 101, 134, 90]
}
]
还有水平柱状图,其实就是把xAxis和yAxis的类型对调一下:
xAxis: {
type: 'value'
},
yAxis: {
type: 'category',
data: ['产品A', '产品B', '产品C', '产品D', '产品E']
}
这样柱子就变成横向的了,适合标签比较长的场景。
饼图:看占比一目了然
饼图适合展示部分占整体的比例关系。比如用户来源分布、预算分配之类的场景。
const pieOption = {
title: {
text: '用户来源分布',
subtext: '近三个月',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: '{b}: {c} ({d}%)' // 显示名称、数值和百分比
},
legend: {
orient: 'vertical',
left: 'left',
top: 'center'
},
series: [
{
name: '来源',
type: 'pie',
radius: ['40%', '70%'], // 甜甜圈效果
center: ['50%', '50%'],
data: [
{ value: 1048, name: '搜索引擎' },
{ value: 735, name: '直接访问' },
{ value: 580, name: '邮件营销' },
{ value: 484, name: '联盟广告' },
{ value: 300, name: '视频广告' }
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
};
这里用radius: ['40%', '70%']做出了一个环形图(甜甜圈效果),比普通饼图更现代一些。formatter里的{b}是名称,{c}是数值,{d}是百分比,这是Echarts内置的模板变量,很好用。
饼图还有一个常见需求是南丁格尔玫瑰图,就是把半径根据数据值动态变化:
series: [
{
name: '访问来源',
type: 'pie',
radius: '55%',
roseType: 'area', // 启用玫瑰图模式
data: [
{ value: 1048, name: '搜索引擎' },
{ value: 735, name: '直接访问' },
{ value: 580, name: '邮件营销' },
{ value: 484, name: '联盟广告' },
{ value: 300, name: '视频广告' }
]
}
]
Vue集成:两种姿势选一种
姿势一:用vue-echarts组件(推荐新手)
这是最简单的方式,官方封装好的组件,用法和普通Vue组件一样:
<template>
<div class="chart-container">
<v-chart :option="option" :auto-resize="true" />
</div>
</template>
<script setup>
import { ref } from 'vue'
import VChart from 'vue-echarts'
import { use } from 'echarts/core'
import { CanvasRenderer } from 'echarts/renderers'
import { LineChart, BarChart, PieChart } from 'echarts/charts'
import {
TitleComponent,
TooltipComponent,
LegendComponent,
GridComponent
} from 'echarts/components'
// 注册必要的模块
use([
CanvasRenderer,
LineChart,
BarChart,
PieChart,
TitleComponent,
TooltipComponent,
LegendComponent,
GridComponent
])
const option = ref({
title: { text: '数据趋势' },
tooltip: { trigger: 'axis' },
xAxis: {
type: 'category',
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
},
yAxis: { type: 'value' },
series: [{
type: 'line',
smooth: true,
data: [120, 132, 101, 134, 90, 230, 210]
}]
})
</script>
<style scoped>
.chart-container {
width: 100%;
height: 400px;
}
</style>
注意这里用了按需引入的方式,只注册你需要的图表类型和组件。这样打包出来的体积会小很多。如果你的项目里同时用了折线图和柱状图,就把LineChart和BarChart都加进去。
姿势二:原生echarts在Vue中使用
有些人不喜欢额外引入组件库,想在Vue里直接用原生API,也是完全可以的:
<template>
<div ref="chartRef" class="chart-container"></div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import * as echarts from 'echarts'
const chartRef = ref(null)
let chartInstance = null
onMounted(() => {
chartInstance = echarts.init(chartRef.value)
chartInstance.setOption({
title: { text: '实时数据' },
tooltip: { trigger: 'axis' },
xAxis: {
type: 'category',
data: ['1月', '2月', '3月', '4月', '5月', '6月']
},
yAxis: { type: 'value' },
series: [{
type: 'bar',
data: [120, 200, 150, 80, 70, 110],
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#83bff6' },
{ offset: 0.5, color: '#188df0' },
{ offset: 1, color: '#188df0' }
])
}
}]
})
})
onUnmounted(() => {
// 记得销毁实例,防止内存泄漏
chartInstance?.dispose()
})
</script>
这里有个关键点:onUnmounted里一定要调用dispose()。很多新手在这里栽跟头,组件销毁了但Echarts实例还留着,时间一长内存就溢出了。
常见问题排查:那些年踩过的坑
问题一:图表不显示,白茫茫一片
这是新手最常遇到的问题。可能的原因有几个:
DOM没准备好就初始化:如果你在
created钩子里调用echarts.init,这时候DOM还没渲染出来,拿到的元素可能是空的。一定要等mounted之后再初始化。容器没有设置高度:Echarts默认不会自动撑开容器,你必须在CSS里给容器设置明确的高度,否则高度为零,图表就看不见了。
.chart-container {
width: 100%;
height: 400px; /* 必须有高度 */
}
- CDN引入时版本问题:如果你用的是CDN引入,检查script标签的顺序,确保echarts.js在业务代码之前加载。
问题二:图表尺寸不对,变形或被截断
// 监听窗口变化,让图表自适应
window.addEventListener('resize', () => {
chartInstance.resize()
})
如果用vue-echarts,直接加auto-resize属性就自动处理了。如果是原生方式,记得在组件销毁时也移除监听:
onUnmounted(() => {
window.removeEventListener('resize', handleResize)
chartInstance.dispose()
})
问题三:数据更新了但图表没变化
在Vue里,如果你直接修改了option里的数据,图表可能不会自动更新。这是因为Echarts的option对象没有被重新引用。解决方法:
// 方式一:用echarts的setOption,传入新的数据
chartInstance.setOption({
series: [{ data: newData }]
})
// 方式二:在Vue里用ref包装整个option,确保响应式
const option = ref({
// ...
})
// 数据更新时
option.value = { ...option.value, series: [{ data: newData }] }
问题四:中文乱码
这个一般出现在用CDN引入或者字体文件缺失的情况。确保你的HTML头文件里有:
<meta charset="UTF-8">
而且如果你用了自定义字体或者特殊字符,检查一下字体文件是否加载成功。
问题五:按需引入后报”Cannot read properties of undefined”
这说明你没有注册对应的组件。Echarts的按需引入需要手动注册所有用到的模块,少一个都可能报错。检查一下你的use()调用里是否包含了所有需要的组件和图表类型。
让图表更美观的一些小技巧
渐变色填充
折线图下面加渐变填充,视觉效果会好很多:
series: [{
type: 'line',
data: [120, 132, 101, 134, 90],
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(64, 158, 255, 0.5)' },
{ offset: 1, color: 'rgba(64, 158, 255, 0.05)' }
])
}
}]
自定义颜色主题
Echarts内置了几套主题,也可以自定义:
// 使用内置主题
const chart = echarts.init(dom, 'dark')
// 或者自定义
echarts.registerTheme('myTheme', {
backgroundColor: '#f5f5f5',
textStyle: { color: '#333' },
color: ['#5470c6', '#91cc75', '#fac858', '#ee6666']
})
添加交互事件
图表不只是看,还能交互。比如点击饼图的某个扇区跳转到详情页:
chartInstance.on('click', (params) => {
console.log('点击了:', params.name)
// 可以路由跳转、弹出详情等
})
总结几句
做Echarts数据可视化其实没那么难,核心就是理解option配置项的结构。title、tooltip、legend、grid、xAxis、yAxis、series,这几个是大框架,series里的type决定画什么图,data决定画什么数据。
一开始别追求花里胡哨的效果,先把折线图、柱状图、饼图这三件套玩熟,遇到具体需求再去查文档。Echarts的文档写得其实挺清楚的,搜索”echarts 折线图 例子”就能找到很多现成的配置。
记住几个关键点:容器要给高度、按需引入要注册全、记得销毁实例、响应式要监听resize。把这四点做好了,十有八九不会再踩大坑。
图表做出来之后,多看看别人的作品找找灵感,像Echarts官方的例子 gallery 就很不错。慢慢你就会发现,数据可视化其实是个挺有意思的事——把冷冰冰的数字变成一眼能看懂的图形,这种”翻译”能力在工作中特别有价值。
