Vue3自定义Echars组件附带全局配置方式
作者:Circle_Key
这篇文章主要介绍了Vue3自定义Echars组件附带全局配置方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
Vue3自定义Echars组件附带全局配置
<template>
<div ref="chart" :id="id" :class="className" :style="{ height: height, width: width }"></div>
</template>
<script setup>
import { ref, reactive, toRefs, onMounted, onBeforeUnmount,watch } from 'vue'
import * as echarts from 'echarts';
// 传递参数
const props = defineProps({
className: {
type: String,
default: 'chart'
},
id: {
type: String,
default: 'chart'
},
width: {
type: String,
default: '100%'
},
height: {
type: String,
default: '280px'
},
options: {
type: Object,
default: () => { }
}
})
const chart = ref(null);
const createChart = () => {
const myChart = echarts.init(chart.value);
chart.value = echarts.init(chart.value, 'tdTheme')
myChart.setOption(props.options,true);
// chart.value.setOption(props.options, true)
window.addEventListener("resize", () => {
chart.value.resize()
})
};
watch(() => props.options, (options) => {
if (chart.value) {
// 设置true清空echart缓存
chart.value.setOption(options, true)
}
}, { deep: true })
onMounted(() => {
createChart();
});
onBeforeUnmount(() => {
window.removeEventListener("resize", () => {
chart.value.resize()
})
chart.value.dispose()
chart.value = null
})
</script>import Echart from './components/echart/index.vue'
import echarts from 'echarts'
const app = createApp(App)
// 将echarts挂载到全局对象上
app.config.globalProperties.$echarts = echarts
// 注册全局组件
app.component('Echart', Echart)案列
<template>
<div ref="chart" style="width: 600px; height: 400px;"></div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import * as echarts from 'echarts';
const chart = ref(null);
const createChart = () => {
const myChart = echarts.init(chart.value);
myChart.setOption({
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value'
},
series: [{
data: [120, 200, 150, 80, 70, 110, 130],
type: 'bar'
}]
});
};
onMounted(() => {
createChart();
});
</script>vue3封装echarts组件
在开发项目过程中需要封装echarts组件,方便多次使用,以下是封装的详细过程。
前置动作:安装echarts以及resize-observer-polyfill插件
- 新建echarts.ts文件
import * as echarts from "echarts/core";
/**
* 这里按需引入使用到的图表类型
*/
import { BarChart, LineChart, type LineSeriesOption, PieChart, type PieSeriesOption } from "echarts/charts";
/**
* 这里按需引入使用到的配置
* 特别地 包括MarkPoint markLine等这些也要单独使用 不然在图表中无法显示
*/
import {
LegendComponent,
type LegendComponentOption,
TitleComponent,
// 组件类型的定义后缀都为 ComponentOption
type TitleComponentOption,
TooltipComponent,
type TooltipComponentOption,
GridComponent,
type GridComponentOption,
DataZoomComponent,
type DataZoomComponentOption,
// 数据集组件
DatasetComponent,
type DatasetComponentOption,
// 标记组件
MarkAreaComponent,
type MarkAreaComponentOption,
MarkLineComponent,
type MarkLineComponentOption,
MarkPointComponent,
type MarkPointComponentOption,
// 内置数据转换器组件 (filter, sort)
TransformComponent,
} from "echarts/components";
import { LabelLayout, UniversalTransition } from "echarts/features";
import { CanvasRenderer } from "echarts/renderers";
import { ref, shallowRef, onMounted, onBeforeUnmount } from "vue";
import ResizeObserver from "resize-observer-polyfill";
import throttle from "lodash/throttle";
/**
* 引入的配置通过 ComposeOption 来组合出一个只有必须组件和图表的 Option 类型
*/
export type ECOption = echarts.ComposeOption<
| LineSeriesOption
| PieSeriesOption
| LegendComponentOption
| TitleComponentOption
| TooltipComponentOption
| DataZoomComponentOption
| GridComponentOption
| DatasetComponentOption
| MarkAreaComponentOption
| MarkLineComponentOption
| MarkPointComponentOption
>;
/**
* 注册按需引入的组件
*/
echarts.use([
LegendComponent,
TitleComponent,
TooltipComponent,
GridComponent,
DataZoomComponent,
DatasetComponent,
MarkAreaComponent,
MarkLineComponent,
MarkPointComponent,
TransformComponent,
BarChart,
LineChart,
PieChart,
LabelLayout,
UniversalTransition,
CanvasRenderer,
]);
export default function useChart() {
const canvasEl = shallowRef();
const myChart = shallowRef();
/**
* 监听容器宽度变化或者浏览器窗口变化对echarts图表进行自动展示
* 不用window.addEventListener("resize", resizeFn)的原因是这个方法只是监听浏览器窗口的不变化
* -对所在容器的大小变化不进行监听 很难满足开发场景的需求
*/
const resizeObserver = ref<ResizeObserver>();
const bindResize = () => {
const deboundResize = throttle(() => {
myChart.value?.resize();
}, 500);
resizeObserver.value = new ResizeObserver(() => {
deboundResize();
// myChart.value?.resize();
});
resizeObserver.value.observe(canvasEl.value);
};
// 解绑 resize
const unbindResize = () => {
resizeObserver.value?.unobserve(canvasEl.value);
};
onMounted(() => {
/**
* 注册echarts并开启监听容器大小变化
*/
myChart.value = echarts.init(canvasEl.value);
bindResize();
});
onBeforeUnmount(() => {
/**
* 销毁监听和echarts
*/
unbindResize();
myChart.value?.dispose();
myChart.value = null;
});
return {
myChart,
canvasEl,
};
}
- 页面封装
<template>
<div>
<div class="chart-container" :style="containerStyle">
<div v-show="dataEmptyFlag" class="chart-empty">
<span class="empty-title">暂无数据</span>
</div>
<div ref="canvasEl" :style="containerStyle" />
<div v-show="loading" class="chart-loading"><Spin /></div>
</div>
</div>
</template>
<script setup lang="ts">
import { Spin } from "ant-design-vue";
import { ref, watch } from "vue";
import useChart from "./useECharts";
import type { ECOption } from "./useECharts";
interface ChartProps {
containerStyle?: any;
loading?: boolean;
dataEmptyFlag?: boolean;
options?: ECOption;
}
const props = withDefaults(defineProps<ChartProps>(), {
containerStyle: {
height: "990px",
width: "100%",
},
loading: false,
dataEmptyFlag: false,
});
const { myChart, canvasEl } = useChart();
watch(
() => props?.options,
(cur) => {
if (myChart) {
/**
* 这里绘制图表前先清空上一次数据 否则有时候会出现数据残余的情况
*/
myChart.value.clear();
myChart.value.setOption(cur);
}
},
);
</script>
<style scoped>
.chart-container {
position: relative;
width: 100%;
}
.chart-loading {
align-items: center;
background-color: #ffffff;
bottom: 0;
display: flex;
justify-content: center;
left: 0;
position: absolute;
right: 0;
top: 0;
z-index: 1999;
}
.chart-empty {
position: absolute;
z-index: 1;
left: 0;
right: 0;
top: 0;
bottom: 0;
color: #888;
font-size: 14px;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.empty-title {
font-size: 16px;
font-weight: 500;
color: #000;
}
</style>
- 组件调用
/** * 参入对应的参数以及图表配置项 */ <anewCharts :loading="loading" :data-empty-flag="dataEmptyFlag" :containerStyle="chartStyle" :options="chartOptions"></anewCharts>
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
