vue3 封装echarts
因为很早前接触echarts 都是在原生js 中使用,所以不太喜欢vue 的一些封装库,因此便于开发,封装一个适合个人的方法组件。
创建模版组件
/Echarts/index.vue
<template>
<div :id="id" :class="className" :style="{ height, width }"></div>
</template>
<script setup lang="ts">
// 按需导入需要用到的 vue函数 和 echarts
import {
onMounted,
onUnmounted,
onBeforeUnmount,
defineProps,
watch,
ref,
defineEmits,
defineExpose,
} from 'vue';
import * as echarts from 'echarts';
// 获取 dom 和 父组件数据 并定义"myChart"用于初始化图表
let myChart: echarts.ECharts;
const props = defineProps({
id: {
type: String,
default: 'chart',
required: true,
},
className: {
type: String,
default: '',
},
width: {
type: String,
default: '100%',
},
height: {
type: String,
default: '300px',
},
loading: {
type: Boolean,
default: true,
},
fullOptions: {
type: Object,
default: () => ({}),
required: true,
},
});
// 重绘图表函数
const resizeHandler = () => {
myChart.resize();
};
// 传出 实例
const chartObj = () => {
return myChart;
};
// 设置防抖,保证无论拖动窗口大小,只执行一次获取浏览器宽高的方法
const debounce = (fun: { (): void; (): void }, delay: number | undefined) => {
let timer: number | undefined;
return function () {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
fun();
}, delay);
};
};
const cancalDebounce = debounce(resizeHandler, 50);
const emit = defineEmits(['legendselectchange']);
// 页面成功渲染,开始绘制图表
onMounted(() => {
// 配置为 svg 形式,预防页面缩放而出现模糊问题;图表过于复杂时建议使用 Canvas
myChart = echarts.init(document.getElementById(props.id) as HTMLDivElement, {
renderer: 'svg',
});
// props.loading &&
// myChart.showLoading({
// text: '',
// color: '#409eff',
// textColor: '#000',
// maskColor: 'rgba(255, 255, 255, .95)',
// zlevel: 0,
// lineWidth: 2,
// });
// if (!props.loading) {
// myChart.hideLoading();
myChart.setOption(props.fullOptions.options, true);
// }
// 自适应不同屏幕时改变图表尺寸
window.addEventListener('resize', cancalDebounce);
// 监听图例的选中状态切换事件
myChart.on('legendselectchanged', function (params) {
console.log('legendselectchanged', params);
emit('legendselectchange', params);
});
});
// 页面销毁前,销毁事件和实例
onBeforeUnmount(() => {
window.removeEventListener('resize', cancalDebounce);
myChart?.dispose();
});
defineExpose({ resizeHandler, chartObj });
// 监听图表数据时候变化,重新渲染图表
watch(
() => [props.fullOptions.options, props.loading],
() => {
// if (!props.loading) {
// myChart.hideLoading();
myChart.setOption(props.fullOptions.options, true);
// }
},
{ deep: true }
);
</script>
创建配置文件
/Echarts/options.vue
// 图表默认配置项
const defaultOption = {
grid: {
left: '3%',
right: '2%',
bottom: '15',
containLabel: true,
},
legend: {
show: false,
top: 'bottom',
textStyle: {
color: '#999',
},
},
tooltip: {
trigger: 'axis',
axisPointer: {
//坐标轴指示器,坐标轴触发有效,
type: 'shadow', //默认为line,line直线,cross十字准星,shadow阴影
crossStyle: {
color: '#fff',
},
label: {
show: true,
backgroundColor: '#333',
},
},
},
};
// 所有用到的 echarts option 都在这里进行配置
export const chartOption = {
// 饼图
pieOption(data: any, dimensions = ['name', 'value'], isRose = false) {
const option = {
...defaultOption,
tooltip: {
trigger: 'item',
formatter: '{b} : {d}%',
},
dataset: {
dimensions: dimensions,
source: data ? data : [{ value: 0, name: '-' }],
},
series: {
type: 'pie',
radius: ['50%', '65%'],
center: ['50%', '50%'],
roseType: isRose ? 'area' : '', // 玫瑰图
itemStyle: {
borderRadius: 1,
// color: function (params: any) {
// //自定义颜色
// const colorList = ['#409EFF', '#67C23A', '#E6A23C', '#F56C6C'];
// return colorList[params.dataIndex];
// }
},
encode: {
itemName: dimensions[0],
value: dimensions[1],
tooltip: dimensions[1],
},
},
};
return option;
},
// 柱状图
barLineOption(xData: any, sData: any, type = 'bar') {
const option = {
...defaultOption,
xAxis: {
type: 'category',
data: xData ? xData : ['-', '-', '-', '-', '-'],
axisLabel: {
interval: 0, // 强制显示所有标签
textStyle: {
// color: '#fff',
},
},
},
yAxis: {
type: 'value',
nameTextStyle: {
padding: [0, 20, 0, 0],
},
min: 0,
minInterval: 1,
axisLabel: {
interval: 0, // 强制显示所有标签
textStyle: {
color: '#8FADCC',
},
},
splitLine: {
show: true,
lineStyle: {
// 分割线的颜色
color: 'rgba(1,1,1,0.5)',
// 分割线的宽度
width: 1,
// 分割线的类型
type: 'solid',
},
},
},
series: {
type: type,
itemStyle: {},
smooth: true,
data: sData ? sData : [0, 0, 0, 0, 0],
},
};
return option;
},
// 柱状图
barLineOption2(yData: any, sData: any, type = 'bar') {
const option = {
...defaultOption,
xAxis: {
type: 'value',
nameTextStyle: {
padding: [0, 20, 0, 0],
},
min: 0,
max: function (value) {
return value.max + 20;
},
},
yAxis: {
type: 'category',
splitLine: {
show: true,
lineStyle: {
// 分割线的颜色
color: '#ddd',
// 分割线的类型
type: 'dashed',
},
},
data: yData ? yData : ['-', '-', '-', '-', '-'],
},
series: {
type: type,
itemStyle: {},
data: sData ? sData : [0, 0, 0, 0, 0],
},
};
return option;
},
};
// x轴方向 滚动条
export const dataZoom = [
{
type: 'slider',
width: '80%',
zoomLock: true, // 是否只平移不缩放
moveOnMouseMove: true, // 鼠标移动能触发数据窗口平移
zoomOnMouseWheel: false, // 鼠标移动能触发数据窗口缩放
// start: 0,
// end: 60,
// startValue: 0,
// endValue: 10,
maxValueSpan: 9,
minValueSpan: 9,
showDataShadow: false,
fillerColor: '#DADADA',
borderRadius: '50%',
moveHandleSize: 0,
moveHandleStyle: {},
left: '10%',
right: '10%',
bottom: 10,
height: 10,
handleSize: '80%', // 滑动条的 左右2个滑动条的大小
handleIcon: 'path://M512,512m-448,0a448,448,0,1,0,896,0a448,448,0,1,0,-896,0Z',
handleStyle: {
borderWidth: 0, // 边框宽度
color: '#DADADA',
},
brushSelect: false,
textStyle: false,
},
{
type: 'inside',
zoomOnMouseWheel: false, // 关闭滚轮缩放
moveOnMouseWheel: true, // 开启滚轮平移
moveOnMouseMove: true, // 鼠标移动能触发数据窗口平移
zoomLock: false,
brushSelect: false,
},
];
// y轴方向滚动条
export const dataZoomY = [
{
type: 'slider',
zoomLock: true, // 是否只平移不缩放
moveOnMouseMove: true, // 鼠标移动能触发数据窗口平移
zoomOnMouseWheel: false, // 鼠标移动能触发数据窗口缩放
start: 100,
// end: 10,
maxValueSpan: 5,
minValueSpan: 5,
showDataShadow: false,
fillerColor: '#DADADA',
borderRadius: '50%',
yAxisIndex: 0,
moveHandleSize: 0,
moveHandleStyle: {},
left: '10',
right: '10',
bottom: 20,
top: 18,
width: 10,
handleSize: '80%', // 滑动条的 左右2个滑动条的大小
handleIcon: 'path://M512,512m-448,0a448,448,0,1,0,896,0a448,448,0,1,0,-896,0Z',
handleStyle: {
borderWidth: 0, // 边框宽度
color: '#DADADA',
},
brushSelect: false,
textStyle: false,
},
{
type: 'inside',
zoomOnMouseWheel: true, // 关闭滚轮缩放
moveOnMouseWheel: true, // 开启滚轮平移
moveOnMouseMove: true, // 鼠标移动能触发数据窗口平移
yAxisIndex: 0,
zoomLock: false,
brushSelect: false,
},
];
使用
<template>
<v-card class="energy_used" title="Energy Used">
<ECharts :height="`calc(${props?.height} - 52px)`" :full-options="options" />
</v-card>
</template>
<script setup lang="ts">
// import VueApexCharts from 'vue3-apexcharts';
import { ref, computed, onMounted, reactive } from 'vue';
import ECharts from '@/components/Echarts/index.vue';
import { chartOption } from '@/components/Echarts/options';
const props = withDefaults(
defineProps<{
height?: string | number;
}>(),
{
height: 308,
}
);
const series = ref([
{
name: 'Kwh',
data: [31, 40, 28, 51, 42, 109, 100],
},
]);
onMounted(() => {
initChart();
});
const options = reactive({
options: {},
});
function initChart() {
const xData = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
const sData = [31, 40, 28, 51, 42, 109, 100];
const option = chartOption.barLineOption(xData, sData);
option.yAxis['name'] = 'Kwh';
option.series.type = 'line';
options.options = option;
}
</script>
这是我自己比较喜欢的一种方式。