vue3+vite,封装 echarts 组件以及如何使用

1.封装 echarts 组件

1.安装 echarts 所需 npm 包,如下。
npm i echarts@5.4.3
npm i echarts-liquidfill@3.1.0 //社区图等
npm i @vueuse/core@10.7.1 //一些好用的hook

2.封装 echarts 组件

1.在 component 目录下新建 Echarts 文件夹
2.在Echarts 文件夹下新建 config 文件夹(按需引入 echarts)
3.config 文件夹新建 index.ts 文件,配置如下
import * as echarts from 'echarts/core';
import { BarChart, LineChart, LinesChart, PieChart, ScatterChart, RadarChart, GaugeChart } from 'echarts/charts';
import {
  TitleComponent,
  TooltipComponent,
  GridComponent,
  DatasetComponent,
  TransformComponent,
  LegendComponent,
  PolarComponent,
  GeoComponent,
  ToolboxComponent,
  DataZoomComponent,
} from 'echarts/components';
import { LabelLayout, UniversalTransition } from 'echarts/features';
import { CanvasRenderer } from 'echarts/renderers';
import 'echarts-liquidfill';

echarts.use([
  TitleComponent,
  TooltipComponent,
  GridComponent,
  DatasetComponent,
  TransformComponent,
  LegendComponent,
  PolarComponent,
  GeoComponent,
  ToolboxComponent,
  DataZoomComponent,
  BarChart,
  LineChart,
  LinesChart,
  PieChart,
  ScatterChart,
  RadarChart,
  GaugeChart,
  LabelLayout,
  UniversalTransition,
  CanvasRenderer,
]);

export default echarts;
4.在 Echarts 目录下,新建 index.vue 文件,封装如下
<template>
  <div id="echarts" ref="chartRef" :style="echartsStyle" />
</template>

<script setup lang="ts" name="ECharts">
import { ref, onMounted, onBeforeUnmount, watch, computed, markRaw, nextTick } from "vue";
import echarts from "./config";
import { useDebounceFn } from "@vueuse/core";

interface Props {
  option: any;
  renderer?: "canvas" | "svg";
  resize?: boolean;
  theme?: Object | string;
  width?: number | string;
  height?: number | string;
  onClick?: (event: any) => any;
}

const props = withDefaults(defineProps<Props>(), {
  renderer: "canvas",
  resize: true
});

const echartsStyle = computed(() => {
  return props.width || props.height
	? { height: props.height + "px", width: props.width + "px" }
	: { height: "100%", width: "100%" };
});

const chartRef = ref<HTMLDivElement | HTMLCanvasElement>();
const chartInstance = ref();

const draw = () => {
  if (chartInstance.value) {
	chartInstance.value.setOption(props.option, { notMerge: true });
  }
};

watch(props, () => {
  draw();
});

const handleClick = (event: any) => props.onClick && props.onClick(event);

const init = () => {
  if (!chartRef.value) return;
  chartInstance.value = echarts.getInstanceByDom(chartRef.value);

  if (!chartInstance.value) {
	chartInstance.value = markRaw(
	  echarts.init(chartRef.value, props.theme, {
		renderer: props.renderer
	  })
	);
	chartInstance.value.on("click", handleClick);
	draw();
  }
};

const resize = () => {
  if (chartInstance.value && props.resize) {
	chartInstance.value.resize({ animation: { duration: 300 } });
  }
};

const debouncedResize = useDebounceFn(resize, 300, { maxWait: 800 });

onMounted(() => {
  nextTick(() => init());
  window.addEventListener("resize", debouncedResize);
});

onBeforeUnmount(() => {
  chartInstance.value?.dispose();
  window.removeEventListener("resize", debouncedResize);
});

defineExpose({
  getInstance: () => chartInstance.value,
  resize,
  draw
});
</script>

3.如何使用(任何新建 index.vue)

<template>
  <div class="echarts">
	<ECharts :option="option" :resize="false" />
  </div>
</template>

<script setup lang="ts">
import ECharts from '@/components/ECharts/index.vue';

const option = {
  title: [
	{
	  text: (0.5 * 100).toFixed(0) + '%',
	  left: '49%',
	  top: '35%',
	  textAlign: 'center',
	  textStyle: {
		fontSize: '16',
		fontWeight: 'normal',
		color: '#ffffff',
		align: 'center',
		textBorderColor: 'rgba(0, 0, 0, 0)',
		textShadowColor: '#000',
		textShadowBlur: 0,
		textShadowOffsetX: 0,
		textShadowOffsetY: 1,
	  },
	},
	{
	  text: '预约量',
	  left: '49%',
	  top: '25%',
	  textAlign: 'center',
	  textStyle: {
		fontSize: '15',
		fontWeight: 'normal',
		color: '#ffffff',
		align: 'center',
		textBorderColor: 'rgba(0, 0, 0, 0)',
		textShadowColor: '#000',
		textShadowBlur: 0,
		textShadowOffsetX: 0,
		textShadowOffsetY: 1,
	  },
	},
  ],
  grid: {
	top: '0',
	left: '0px',
	right: '0px',
	bottom: '0',
	containLabel: true,
  },
  polar: {
	radius: ['75%', '85%'],
	center: ['50%', '50%'],
  },
  angleAxis: {
	max: 120,
	clockwise: false,
	axisLine: {
	  show: false,
	},
	axisTick: {
	  show: false,
	},
	axisLabel: {
	  show: false,
	},
	splitLine: {
	  show: false,
	},
	startAngle: 188,
  },
  radiusAxis: {
	type: 'category',
	show: true,
	axisLabel: {
	  show: false,
	},
	axisLine: {
	  show: false,
	},
	axisTick: {
	  show: false,
	},
  },
  series: [
	{
	  type: 'liquidFill',
	  radius: '70%',
	  z: 2,
	  center: ['50%', '50%'],
	  data: [0.4, 0.4, 0.4],
	  itemStyle: {
		color: {
		  type: 'linear',
		  x: 0,
		  y: 0,
		  x2: 0,
		  y2: 1,
		  colorStops: [
			{ offset: 0, color: '#35FAB6' },
			{ offset: 1, color: 'rgba(40, 209, 247,0.3)' },
		  ],
		  global: false,
		},
	  },
	  outline: {
		borderDistance: 0,
		itemStyle: {
		  borderWidth: 2,
		  borderColor: '#31d8d5',
		  shadowBlur: 20,
		  shadowColor: '#50c1a7',
		},
	  },
	  label: {
		show: false,
	  },
	  backgroundStyle: {
		borderWidth: 1,
		color: {
		  type: 'radial',
		  x: 0.5,
		  y: 0.5,
		  r: 0.5,
		  colorStops: [
			{ offset: 0, color: '#0D2648' },
			{ offset: 0.8, color: '#0D2648' },
			{ offset: 1, color: '#228E7D' },
		  ],
		  global: false,
		},
	  },
	},
	{
	  type: 'pie',
	  radius: ['80%', '80%'],
	  center: ['50%', '50%'],
	  z: 1,
	  label: { show: false },
	  silent: true,
	  itemStyle: {
		borderWidth: 2,
		borderType: [8, 10],
		borderDashOffset: 15,
		borderColor: '#31d8d5',
		color: '#11144e',
		borderCap: 'round',
	  },
	  data: [100],
	},
	{
	  type: 'bar',
	  data: [55],
	  z: 10,
	  coordinateSystem: 'polar',
	  roundCap: true,
	  color: '#31d8d5',
	},
  ],
};
</script>

<style lang="less" scoped>
.echarts {
  width: 100%;
  height: calc(100% - 50px);
}
</style>
posted @ 2024-03-01 16:25  SKa-M  阅读(1166)  评论(0编辑  收藏  举报