近期我负责的公司人力资源系统中,薪酬统计模块的开发进度正稳步推进。在此过程中,我发现需要展示多种图表(如 ECharts)来直观反映数据。然而,ECharts 的配置过程相对复杂,频繁查阅官方文档不仅耗时,而且效率不高。为了提升开发效率,我萌生了这样一个想法:将 ECharts 中的一些通用属性进行提炼和整理,同时汇总常用的配置项以及在实际应用中需要注意的要点。这样一来,不仅能够简化配置过程,还能为团队提供一个便捷的参考指南。
EChart 资源
Vue-EChart
不想封装 Echart, 可以选用这种方案。
Vue-ECharts 是一个 Vue 组件,旨在简化在 Vue 应用中集成 ECharts 的过程。它封装了 ECharts 的初始化和使用逻辑,用户只需要在 Vue 模板中添加组件并传递相应的 props,即可轻松创建图表。
支持Vue2 & Vue3 & Nuxt3
DOC: https://github.com/ecomfe/vue-echarts#readme

优点:
- Vue-ECharts 组件会自动处理 ECharts 实例的生命周期,能够根据 Vue 组件的状态变化自动更新图表。这使得代码更加简洁,易于维护。
- 通过 Vue 的数据绑定机制,可以直接将数据绑定到组件的 props 上,Vue-ECharts 会自动将数据变化应用到图表上。
- 作为 Vue 组件,可以很容易地与其他 Vue 组件组合,并且可以利用 Vue 的指令和事件系统。
EChart 配置生成 option
目前只有三种图表状态,可生成图片和JSON.
https://github.com/BruceHenry/chart-creator

EChart 速查手册 [官网]
https://echarts.apache.org/zh/cheat-sheet.html

EChart 主题配置 [官网]
https://echarts.apache.org/zh/theme-builder.html

EChart 社区示例 [社区,提供了大量的示例基本可以满足任何需求]
- MCChart

- isqqw

- MakeAPie

- PPChart

阅读导图

常用属性配置
title 标题配置

- text - 标题文本,例如 "柱状图"
- subtext- 副标题文本***
- *left 标题的水平位置,可以是像'left' 'center' 'right' 或者像'20%' 这样的百分比
- top*** **- 标题的垂直位置,可以是像** **'top',**** __'middle'__,__** __'bottom'__** __或者像**__** __'20%'__ __这样的百分比***
- textStyle*** **- 控制标题文本样式的对象,可以包括** ****color****,fontStyle,fontWeight,fontFamily,*fontSize****** ****等
- subtextStyle*** **- 控制副标题文本样式的对象,属性同** ****textStyle*
- textAlign*** **- 标题文本对齐,例如** **'left',**** __'right'__,**__** __'center'***
- padding*** **- 标题内边距,可以是数字或数组** ****[上, 右, 下, 左]*
- itemGap - 主副标题之间的间距
option = {
title: {
text: '主标题文本',
subtext: '副标题文本',
left: 'center',
top: 'top',
textStyle: {
color: 'black',
fontStyle: 'normal',
fontWeight: 'bold',
fontFamily: 'Arial',
fontSize: 18,
},
subtextStyle: {
color: '#aaa',
fontStyle: 'normal',
fontWeight: 'normal',
fontFamily: 'Arial',
fontSize: 12,
},
textAlign: 'center',
padding: [5, 10],
itemGap: 10
},
};
- formatter - 提示框浮层的内容格式器,支持字符串模板和回调函数两种形式
- axisPointer - 坐标轴指示器配置,指定其类型如 'line'、'shadow' 等
- show - 是否显示提示框组件,包括提示框浮层和 axisPointer,默认为*** ***true
- backgroundColor - 提示框浮层的背景颜色
- borderColor - 提示框浮层的边框颜色
- borderWidth - 提示框浮层的边框宽
- padding - 提示框浮层内边距,可以是数字或数组 __[上, 右, 下, 左]**
tooltip: {
trigger: 'axis',
formatter: function (params) {
let res = params[0].name + '<br>';
params.forEach(function (item) {
res += item.seriesName + ': ' + item.value + '<br>';
});
return res;
},
axisPointer: {
type: 'shadow'
},
show: true,
backgroundColor: 'rgba(50,50,50,0.7)',
borderColor: '#333',
borderWidth: 0,
padding: 10
},
- formatter - 提示框浮层的内容格式器,支持字符串模板和回调函数两种形式
- axisPointer - 坐标轴指示器配置,指定其类型如 'line'、'shadow' 等
- show - 是否显示提示框组件,包括提示框浮层和 axisPointer,默认为*** ***true
- backgroundColor - 提示框浮层的背景颜色
- borderColor - 提示框浮层的边框颜色
- borderWidth - 提示框浮层的边框宽
- padding - 提示框浮层内边距,可以是数字或数组 __[上, 右, 下, 左]**
tooltip: {
trigger: 'axis',
formatter: function (params) {
let res = params[0].name + '<br>';
params.forEach(function (item) {
res += item.seriesName + ': ' + item.value + '<br>';
});
return res;
},
axisPointer: {
type: 'shadow'
},
show: true,
backgroundColor: 'rgba(50,50,50,0.7)',
borderColor: '#333',
borderWidth: 0,
padding: 10
},
legend(图例组件)

图表的图例,表示不同系列的标识。
legend: {
top: '5%',
left: 'center',
data: ['直接访问', '联盟广告', '搜索引擎']
}
series(系列列表)

每个 series 代表一组数据项的集合,对于饼图配置的主要部分。
series 属性及其可能的值包括:
- type: 'pie' // 必须设置为 'pie' 表示这是一个饼图。
- radius: 半径,可以是百分比或固定像素值,也可以是数组形式表示内外半径。
- center: Pie图的中心位置。
- data: 数据项数组,每个数据项包括 value(数值)和 name(名称)。
- stillShowZeroSum: 如果所有数据值都是0,是否显示图形。
- label: 用于设置数据标签,如是否显示、位置、格式等。
series: [
{
name: '访问来源',
type: 'pie',
radius: '50%',
center: ['50%', '50%'],
data: [
{value: 335, name: '直接访问'},
{value: 234, name: '联盟广告'},
{value: 1548, name: '搜索引擎'}
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
},
stillShowZeroSum: true,
label: {
normal: {
show: true,
position: 'outside'
},
emphasis: {
show: true,
textStyle: {
fontSize: '30',
fontWeight: 'bold'
}
}
}
}
]

color (配色方案)

定义颜色数组,用于系列中每个扇形的默认颜色:
- 示例:
<font style="color:rgb(46, 50, 56);">['#5470C6', '#91CC75', '#FAC858', '#EE6666']</font>
animation (动画配置)

完整配置示例代码
option = {
title: {
text: 'Pie Chart Example'
},
tooltip: {
trigger: 'item'
},
legend: {
top: '5%',
left: 'center',
data: ['Direct Visit', 'Union Ad', 'Search Engine']
},
toolbox: {
show: true,
feature: {
saveAsImage: {},
restore: {}
}
},
series: [
{
name: 'Access From',
type: 'pie',
radius: '55%',
center: ['50%', '60%'],
data: [
{ value: 335, name: 'Direct Visit' },
{ value: 234, name: 'Union Ad' },
{ value: 1548, name: 'Search Engine' }
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
},
label: {
normal: {
show: true,
position: 'outside',
formatter: '{b}: {c} ({d}%)'
},
emphasis: {
show: true,
textStyle: {
fontSize: '30',
fontWeight: 'bold'
}
}
}
}
]
};
EChart 在 Vue3 中实战
const chart = ref(null);
const initChart = () => {
if (chart.value) {
const myChart = echarts.init(chart.value);
myChart.setOption(props.option);
}
};
watch(
() => props.option,
(newOption) => {
if (chart.value) {
const myChart = echarts.getInstanceByDom(chart.value);
myChart.setOption(newOption);
}
}
);
响应式处理
图表在窗口大小变化时能够自动调整。可以使用 resize()
方法手动调整图表大小,通常是在 updated
生命周期钩子中调用。
const resizeChart = () => {
if (chart.value) {
const myChart = echarts.getInstanceByDom(chart.value);
myChart.resize();
}
};
onMounted(() => {
initChart();
window.addEventListener('resize', resizeChart);
});
动态数据更新
使用 Vue 的响应式数据(如 ref
或 reactive
)配合 watch
,在数据变化时调用 chart.setOption()
重新渲染图表。
const chartOption = ref({
title: { text: '实时数据' },
tooltip: { trigger: 'axis' },
xAxis: { data: ['1', '2', '3', '4', '5'] },
yAxis: {},
series: [{
name: '销量',
type: 'line',
data: [120, 132, 101, 134, 90]
}]
});
watch(
() => props.option,
(newOption) => {
if (chartInstance.value) {
chartInstance.value.setOption(newOption);
}
},
{ deep: true }
);
chartOption.value.series[0].data.push(Math.random() * 100);
chartOption.value.xAxis.data.push(String(chartOption.value.xAxis.data.length + 1));
图表容器大小自适应
父容器尺寸发生变化时,图表可能不会自动调整大小。 我们可以通过 监听 resize
事件或使用 Vue 的响应式布局方案,调用 chart.resize()
更新图表尺寸。
const observer = new ResizeObserver(() => {
chartInstance.value?.resize();
});
observer.observe(containerElement);
国际化与多语言支持
图表中包含的文案(如标题、提示)需要支持多语言。 我们可以使用 Vue I18n 或其他国际化工具动态替换文本。
npm install vue-i18n
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const option = reactive({
title: { text: t('chart.title') },
});
ECharts 图表导出
toolbox: {
feature: {
saveAsImage: { show: true },
},
};
性能优化
销毁 ECharts 实例
在组件销毁时,确保销毁 ECharts 实例,防止内存泄漏。
onBeforeUnmount(() => {
if (chart.value) {
const myChart = echarts.getInstanceByDom(chart.value);
myChart.dispose();
}
window.removeEventListener('resize', resizeChart);
});
大数据渲染性能优化
数据量大时,ECharts 的渲染可能会导致性能瓶颈。 我们可以通过以下三种方式来达到优化作用
- 使用
**dataZoom**
: 允许用户缩放数据区域,减少可视数据点。 - 启用分片渲染:
series: [
{
type: 'line',
large: true,
largeThreshold: 4000,
},
];
animation: false,
progressive: 4000,
progressiveThreshold: 10000,
图表配置项太长,分离配置项
配置项代码过长,组件可读性降低。我们可以将配置项提取到单独的模块,便于复用和维护。

EChart 知识点常考
如何初始化和销毁 ECharts 实例?
echarts.init(dom)
初始化。chart.dispose()
销毁实例,避免内存泄漏。
ECharts 常见配置项有哪些?
title
, legend
, tooltip
, grid
, xAxis
, yAxis
, series
, toolbox
, dataZoom
。
动态数据更新
- 如何实现图表数据的动态更新?
- 如何监听 `props` 变化并更新图表配置?
性能优化
- 大数据渲染场景如何优化?
- 什么是 `progressive` 渲染模式?
图表事件
- 如何捕获图表点击、悬停事件并执行对应的业务逻辑?
如何处理数据较多导致渲染卡顿的情况?
- 使用数据分片渲染(
progressive
)。 - 禁用动画。
- 使用
dataZoom
限制显示范围。
如何实现图表导出功能?
使用 toolbox.feature.saveAsImage
或通过 chart.getDataURL()
获取图表数据并导出。
最后
通过对 ECharts 通用属性的深入提炼与系统整理,以及常用配置项的归纳总结,我们能够迅速实现图表的搭建与展示,极大地提升了开发效率。此外,借助丰富的 ECharts 资源和示例,我们基本上能够满足大部分业务场景的需求。这样一来,我们不仅能够更加快捷地实现功能需求,还能腾出更多宝贵的时间,专注于其他重要任务。
转自https://www.cnblogs.com/HaiJun-Aion/p/18569547
该文章在 2025/2/8 10:54:56 编辑过