在Vue2中使用ECharts还是比较麻烦的,今天做了几个组件让我们能更加简单的调用Echars来显示图表。
效果展示
echarts 导入
这里我们使用 package.json 方式导入Echars。配置好后使用命令 npm install或者其他方式都可以
json
{
// ...
"scripts": {
// ...
"setYarn": "yarn config set registry https://registry.npmmirror.com/", // 设置yarn镜像地址
"yarnInstall": "yarn install", // yarn
}
// ...
"dependencies": {
// ...
"echarts": "^5.4.3", // 博主用的是这个版本可根据自己需求修改
}
// ...
}
父组件引用
html
<template>
<div>
<!-- 操作按钮区域 -->
<div>
<a-button @click="loadData" type="primary" icon="sync">刷新</a-button>
</div>
<EBarChart title='MSA偏倚直方图' :data="barData" x-label='测量值' y-label='频数' width="90%" height="500px" />
<ELineChart title='' :data="barData" x-label='测量值' y-label='频数' width="90%" height="500px" />
<EPieChart title='' :data=" [
{ value: 1048, name: '测量值1' },
{ value: 735, name: '测量值2' },
{ value: 580, name: '测量值3' },
]" width="90%" height="500px" />
</div>
</template>
<script>
import { getAction } from '@/api/manage';
import EBarChart from '@comp/EChart/EBarChart.vue';
import ELineChart from '@comp/EChart/ELineChart.vue'
import EPieChart from '@comp/EChart/EPieChart.vue'
export default {
name: '',
components: { ELineChart, EBarChart, EPieChart },
data() {
return {
dataSource: [],
chartOptions: {},
barData: {
x:[],
y:[],
},
url: {
list: '/msa/msaBias/listAllMsaGroupDataByMainId',
},
};
},
methods: {
clearList() {
this.dataSource = [];
},
loadData() {
this.chartOptions = {};
this.barData = {
x: [],
y: []
};
// 这里是请求服务器数据的方式 如果不需要自行修改
getAction(this.url.list, { pid: this.mainId }).then(res => {
if (res.success) {
this.dataSource = res.result.records || res.result;
const xData = this.dataSource.map(item => String(item.minValue)); // 确保是字符串
const yData = this.dataSource.map(item => Number(item.sampleCount)); // 确保是数值
this.barData = {
x: xData,
y: yData
};
} else {
this.$message.error(res.message);
}
});
},
},
};
</script>
<style scoped></style>
柱状图组件
html
<template>
<div ref="chartContainer" :style="{ width: width, height: height }"></div>
</template>
<script>
import * as echarts from 'echarts';
export default {
name: 'EBarChart',
props: {
title: { type: String, default: "柱状图" },
xLabel: { type: String, default: "" },
yLabel: { type: String, default: "" },
options: { type: Object, default: () => ({}) },// 自定义options
data: { type: Object, default: () => ({}) }, // 调用方式{x:[],y:[]}
width: { type: String, default: '100%' },
height: { type: String, default: '400px' },
},
data() {
let xLabel = this.xLabel
let yLabel = this.yLabel
return {
chartInstance: null,
defaultOptions: {
// 标题配置
title: {
text: this.title, // 标题文本
left: 'center', // 标题位置(居中)
top: '0px', // 标题距离图表顶部 20px
textStyle: {
fontSize: 25, // 标题字体大小
fontWeight: 'bold', // 标题字体加粗
color: '#333', // 标题字体颜色
},
},
// 提示框配置
tooltip: {
trigger: 'axis', // 触发方式(坐标轴触发)
backgroundColor: 'rgba(50, 50, 50, 0.7)', // 提示框背景颜色
borderColor: '#333', // 提示框边框颜色
borderWidth: 1, // 提示框边框宽度
padding: 10, // 提示框内边距
textStyle: {
fontSize: 18, // 提示框字体大小
color: '#fff', // 提示框字体颜色
},
formatter: function (params) {
// 自定义提示框内容
return `${yLabel}: ${params[0].name}<br/>${xLabel}: ${params[0].value}`;
},
},
// 图例配置
legend: {
show: true, // 是否显示图例
data: [yLabel], // 图例数据(与 series.name 对应)
left: 'right', // 图例位置(右侧)
textStyle: {
fontSize: 18, // 图例字体大小
color: '#333', // 图例字体颜色
},
},
// 网格配置
grid: {
left: '10%', // 网格左侧距离
right: '10%', // 网格右侧距离
bottom: '15%', // 网格底部距离
top: '15%',
containLabel: true, // 是否包含坐标轴标签
},
// X 轴配置
xAxis: {
type: 'category', // 坐标轴类型(类目轴)
data: [], // 类目数据
axisLabel: {
fontSize: 18, // 标签字体大小
color: '#333', // 标签字体颜色
rotate: 0, // 标签旋转角度
interval: 0, // 强制显示所有标签
},
axisLine: {
lineStyle: {
color: '#333', // 坐标轴线颜色
width: 2, // 坐标轴线宽度
},
},
axisTick: {
show: true, // 是否显示坐标轴刻度
alignWithLabel: true, // 刻度与标签对齐
},
name: xLabel, // 坐标轴名称
nameLocation: 'center', // 坐标轴名称位置(居中)
nameGap: 50, // 坐标轴名称与轴线的距离
nameTextStyle: {
fontSize: 18, // 坐标轴名称字体大小
color: '#333', // 坐标轴名称字体颜色
},
},
// Y 轴配置
yAxis: {
type: 'value', // 坐标轴类型(数值轴)
axisLabel: {
fontSize: 18, // 标签字体大小
color: '#333', // 标签字体颜色
},
axisLine: {
lineStyle: {
color: '#333', // 坐标轴线颜色
width: 2, // 坐标轴线宽度
},
},
axisTick: {
show: true, // 是否显示坐标轴刻度
},
splitLine: {
show: true, // 是否显示分割线
lineStyle: {
color: '#eee', // 分割线颜色
type: 'dashed', // 分割线类型(虚线)
},
},
name: yLabel, // 坐标轴名称
nameLocation: 'center', // 坐标轴名称位置(居中)
nameGap: 50, // 坐标轴名称与轴线的距离
nameTextStyle: {
fontSize: 18, // 坐标轴名称字体大小
color: '#333', // 坐标轴名称字体颜色
},
},
// 数据系列配置
series: [
{
name: yLabel, // 系列名称(与图例对应)
type: 'bar', // 图表类型(柱状图)
data: [], // 数据值
barWidth: 'auto', // 柱状图宽度(自动计算)
barGap: '5px', // 两个柱子之间的宽度
label: {
show: true, // 是否显示标签
position: 'top', // 标签位置(柱状图顶部)
fontSize: 18, // 标签字体大小
color: '#333', // 标签字体颜色
formatter: '{c}', // 标签内容格式(显示数据值)
},
itemStyle: {
color: '#5470C6', // 柱状图颜色
borderColor: '#333', // 柱状图边框颜色
borderWidth: 1, // 柱状图边框宽度
},
},
],
},
};
},
mounted() {
this.initChart();
window.addEventListener('resize', this.handleResize);
},
beforeDestroy() {
window.removeEventListener('resize', this.handleResize);
if (this.chartInstance) this.chartInstance.dispose();
},
methods: {
initChart() {
const dom = this.$refs.chartContainer;
if (!dom) {
console.error('Chart container not found!');
return;
}
this.chartInstance = echarts.init(dom);
const mergedOptions = this.generateOptions();
console.log('initChart:', mergedOptions); // 打印 mergedOptions
this.chartInstance.setOption(mergedOptions);
},
generateOptions() {
let mergedOptions = { ...this.defaultOptions };
if (Object.keys(this.options).length > 0) {
// 方式一:使用用户自定义的 options
mergedOptions = this.options;
} else if (this.data?.x?.length > 0 && this.data?.y?.length > 0) {
// 方式二:使用默认配置,填充 data
mergedOptions.xAxis.data = this.data.x;
mergedOptions.series[0].data = this.data.y;
}
console.log('generateOptions:', mergedOptions); // 打印 mergedOptions
return mergedOptions;
},
handleResize() {
this.chartInstance?.resize();
},
},
watch: {
options: {
deep: true,
handler() {
if (this.chartInstance) {
const mergedOptions = this.generateOptions();
this.chartInstance.setOption(mergedOptions, { notMerge: true }); // 强制更新
}
},
},
data: {
deep: true,
handler() {
if (this.chartInstance) {
const mergedOptions = this.generateOptions();
this.chartInstance.setOption(mergedOptions, { notMerge: true }); // 强制更新
}
},
},
},
};
</script>
折线图组件
html
<template>
<div ref="chartContainer" :style="{ width: width, height: height }"></div>
</template>
<script>
import * as echarts from 'echarts';
export default {
name: 'ELineChart',
props: {
title: { type: String, default: "折线图" },
xLabel: { type: String, default: "" },
yLabel: { type: String, default: "" },
options: { type: Object, default: () => ({}) }, // 自定义options
data: { type: Object, default: () => ({}) }, // 调用方式{x:[],y:[]}
width: { type: String, default: '100%' },
height: { type: String, default: '400px' },
},
data() {
let xLabel = this.xLabel
let yLabel = this.yLabel
return {
chartInstance: null,
defaultOptions: {
// 标题配置
title: {
text: this.title, // 标题文本
left: 'center', // 标题位置(居中)
top: '0px', // 标题距离图表顶部 20px
textStyle: {
fontSize: 25, // 标题字体大小
fontWeight: 'bold', // 标题字体加粗
color: '#333', // 标题字体颜色
},
},
// 提示框配置
tooltip: {
trigger: 'axis', // 触发方式(坐标轴触发)
backgroundColor: 'rgba(50, 50, 50, 0.7)', // 提示框背景颜色
borderColor: '#333', // 提示框边框颜色
borderWidth: 1, // 提示框边框宽度
padding: 10, // 提示框内边距
textStyle: {
fontSize: 18, // 提示框字体大小
color: '#fff', // 提示框字体颜色
},
formatter: function (params) {
// 自定义提示框内容
return `${yLabel}: ${params[0].name}<br/>${xLabel}: ${params[0].value}`;
},
},
// 图例配置
legend: {
show: true, // 是否显示图例
data: [yLabel], // 图例数据(与 series.name 对应)
left: 'right', // 图例位置(右侧)
textStyle: {
fontSize: 18, // 图例字体大小
color: '#333', // 图例字体颜色
},
},
// 网格配置
grid: {
left: '10%', // 网格左侧距离
right: '10%', // 网格右侧距离
bottom: '15%', // 网格底部距离
top: '15%',
containLabel: true, // 是否包含坐标轴标签
},
// X 轴配置
xAxis: {
type: 'category', // 坐标轴类型(类目轴)
data: [], // 类目数据
axisLabel: {
fontSize: 18, // 标签字体大小
color: '#333', // 标签字体颜色
rotate: 0, // 标签旋转角度
interval: 0, // 强制显示所有标签
},
axisLine: {
lineStyle: {
color: '#333', // 坐标轴线颜色
width: 2, // 坐标轴线宽度
},
},
axisTick: {
show: true, // 是否显示坐标轴刻度
alignWithLabel: true, // 刻度与标签对齐
},
name: xLabel, // 坐标轴名称
nameLocation: 'center', // 坐标轴名称位置(居中)
nameGap: 50, // 坐标轴名称与轴线的距离
nameTextStyle: {
fontSize: 18, // 坐标轴名称字体大小
color: '#333', // 坐标轴名称字体颜色
},
},
// Y 轴配置
yAxis: {
type: 'value', // 坐标轴类型(数值轴)
axisLabel: {
fontSize: 18, // 标签字体大小
color: '#333', // 标签字体颜色
},
axisLine: {
lineStyle: {
color: '#333', // 坐标轴线颜色
width: 2, // 坐标轴线宽度
},
},
axisTick: {
show: true, // 是否显示坐标轴刻度
},
splitLine: {
show: true, // 是否显示分割线
lineStyle: {
color: '#eee', // 分割线颜色
type: 'dashed', // 分割线类型(虚线)
},
},
name: yLabel, // 坐标轴名称
nameLocation: 'center', // 坐标轴名称位置(居中)
nameGap: 50, // 坐标轴名称与轴线的距离
nameTextStyle: {
fontSize: 18, // 坐标轴名称字体大小
color: '#333', // 坐标轴名称字体颜色
},
},
// 数据系列配置
series: [
{
name: yLabel, // 系列名称(与图例对应)
type: 'line', // 图表类型(折线图)
data: [], // 数据值
label: {
show: true, // 是否显示标签
position: 'top', // 标签位置(折线图顶部)
fontSize: 18, // 标签字体大小
color: '#333', // 标签字体颜色
formatter: '{c}', // 标签内容格式(显示数据值)
},
itemStyle: {
color: '#5470C6', // 折线图颜色
borderColor: '#333', // 折线图边框颜色
borderWidth: 1, // 折线图边框宽度
},
lineStyle: {
color: '#5470C6', // 折线颜色
width: 2, // 折线宽度
},
symbol: 'circle', // 数据点形状
symbolSize: 8, // 数据点大小
},
],
},
};
},
mounted() {
this.initChart();
window.addEventListener('resize', this.handleResize);
},
beforeDestroy() {
window.removeEventListener('resize', this.handleResize);
if (this.chartInstance) this.chartInstance.dispose();
},
methods: {
initChart() {
const dom = this.$refs.chartContainer;
if (!dom) {
console.error('Chart container not found!');
return;
}
this.chartInstance = echarts.init(dom);
const mergedOptions = this.generateOptions();
console.log('initChart:', mergedOptions); // 打印 mergedOptions
this.chartInstance.setOption(mergedOptions);
},
generateOptions() {
let mergedOptions = { ...this.defaultOptions };
if (Object.keys(this.options).length > 0) {
// 方式一:使用用户自定义的 options
mergedOptions = this.options;
} else if (this.data?.x?.length > 0 && this.data?.y?.length > 0) {
// 方式二:使用默认配置,填充 data
mergedOptions.xAxis.data = this.data.x;
mergedOptions.series[0].data = this.data.y;
}
console.log('generateOptions:', mergedOptions); // 打印 mergedOptions
return mergedOptions;
},
handleResize() {
this.chartInstance?.resize();
},
},
watch: {
options: {
deep: true,
handler() {
if (this.chartInstance) {
const mergedOptions = this.generateOptions();
this.chartInstance.setOption(mergedOptions, { notMerge: true }); // 强制更新
}
},
},
data: {
deep: true,
handler() {
if (this.chartInstance) {
const mergedOptions = this.generateOptions();
this.chartInstance.setOption(mergedOptions, { notMerge: true }); // 强制更新
}
},
},
},
};
</script>
饼图组件
html
<template>
<div ref="chartContainer" :style="{ width: width, height: height }"></div>
</template>
<script>
import * as echarts from 'echarts';
export default {
name: 'EPieChart',
props: {
title: { type: String, default: "饼图" },
options: { type: Object, default: () => ({}) },
data: { type: Object, default: () => ([]) },// 调用方式 [{ value: 1048, name: '测量值1' },...]
width: { type: String, default: '100%' },
height: { type: String, default: '400px' },
},
data() {
return {
chartInstance: null,
defaultOptions: {
// 标题配置
title: {
text: this.title, // 标题文本
left: 'center', // 标题位置(居中)
top: '0px', // 标题距离图表顶部 20px
textStyle: {
fontSize: 25, // 标题字体大小
fontWeight: 'bold', // 标题字体加粗
color: '#333', // 标题字体颜色
},
},
// 提示框配置
tooltip: {
trigger: 'item', // 触发方式(数据项触发)
backgroundColor: 'rgba(50, 50, 50, 0.7)', // 提示框背景颜色
borderColor: '#333', // 提示框边框颜色
borderWidth: 1, // 提示框边框宽度
padding: 10, // 提示框内边距
textStyle: {
fontSize: 18, // 提示框字体大小
color: '#fff', // 提示框字体颜色
},
formatter: function (params) {
// 自定义提示框内容
return `${params.name}: ${params.value} (${params.percent}%)`;
},
},
// 图例配置
legend: {
show: true, // 是否显示图例
left: 'right', // 图例位置(右侧)
textStyle: {
fontSize: 18, // 图例字体大小
color: '#333', // 图例字体颜色
},
},
// 数据系列配置
series: [
{
name: '频数', // 系列名称(与图例对应)
type: 'pie', // 图表类型(饼图)
radius: '50%', // 饼图半径(50%表示占容器的一半)
data: [], // 数据值
label: {
show: true, // 是否显示标签
fontSize: 18, // 标签字体大小
color: '#333', // 标签字体颜色
formatter: '{b}: {c} ({d}%)', // 标签内容格式(显示名称、值和百分比)
},
itemStyle: {
borderColor: '#fff', // 饼图边框颜色
borderWidth: 2, // 饼图边框宽度
},
emphasis: {
// 高亮样式
label: {
show: true,
fontSize: 20,
fontWeight: 'bold',
},
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)',
},
},
},
],
},
};
},
mounted() {
this.initChart();
window.addEventListener('resize', this.handleResize);
},
beforeDestroy() {
window.removeEventListener('resize', this.handleResize);
if (this.chartInstance) this.chartInstance.dispose();
},
methods: {
initChart() {
const dom = this.$refs.chartContainer;
if (!dom) {
console.error('Chart container not found!');
return;
}
this.chartInstance = echarts.init(dom);
const mergedOptions = this.generateOptions();
console.log('initChart:', mergedOptions); // 打印 mergedOptions
this.chartInstance.setOption(mergedOptions);
},
generateOptions() {
let mergedOptions = { ...this.defaultOptions };
if (Object.keys(this.options).length > 0) {
// 方式一:使用用户自定义的 options
mergedOptions = this.options;
} else if (this.data?.length > 0) {
// 方式二:使用默认配置,填充 data
mergedOptions.series[0].data = this.data;
}
console.log('generateOptions:', mergedOptions); // 打印 mergedOptions
return mergedOptions;
},
handleResize() {
this.chartInstance?.resize();
},
},
watch: {
options: {
deep: true,
handler() {
if (this.chartInstance) {
const mergedOptions = this.generateOptions();
this.chartInstance.setOption(mergedOptions, { notMerge: true }); // 强制更新
}
},
},
data: {
deep: true,
handler() {
if (this.chartInstance) {
const mergedOptions = this.generateOptions();
this.chartInstance.setOption(mergedOptions, { notMerge: true }); // 强制更新
}
},
},
},
};
</script>