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>
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。