闲时基于上次封装的图表组件做了一层优化,话不多说,间接上代码吧
Step-1: 新建一个config.ts文件
export const config = { labelKey: "name", valueKey: "value",};export type chartDataItemType = { [key: string]: string | number;};// 以后反对显示的图表类型(折线,柱形)export type chartSupportType = "line" | "bar";export type chartDataType = { name: string; data: chartDataItemType[]; type: chartSupportType; labelKey?: string; valueKey?: string; options?: any;};export type chartOptionsType = { [key: string]: any;};// 根底图例色彩数据export const baseColorArr = [ "#3CD7D7", "#F9CB28", "#A089FF", "#5CC4FF", "#FF9292", "#5CC4FF", "#FF8AEC", "#FFB35B",];// 暗影区域色彩数据export const areaColorArr = [ "#C5F3F3", "#FDEFBF", "#dcd3ff", "#bde7ff", "#ffd3d3", "#bde7ff", "#ffd0f7", "#ffe0bd",];// 图例顶部字体大小export const defaultLabelFontsize = 8;export const getColor = (index, type: "default" | "area" = "default") => { const colorArr = type === "default" ? baseColorArr : areaColorArr; const colorIndex = index % colorArr.length; return colorArr[colorIndex];};// 图表底部滚动条默认款式export const defaultDataZoomOptions: any[] = [ { type: "slider", show: true, xAxisIndex: [0], start: 0, end: 30, textStyle: { color: "#ccd7d7", }, },];// 获取滚动条款式export const getDataZoom = (seriesLength, showZoomLength) => { if (seriesLength > showZoomLength) { return defaultDataZoomOptions; } else { return []; }};// 获取折线图、柱形图根底配置export const getLineBarBaseOptions = (seriesLength, showZoomLength = 7) => { return { tooltip: { trigger: "axis", axisPointer: { type: "shadow", }, }, grid: { left: "3%", right: "4%", bottom: "3%", containLabel: true, }, yAxis: { type: "value", }, dataZoom: getDataZoom(seriesLength, showZoomLength), };};// 获取折线系列配置export const getLineSeriesOptions = (index) => { return { tooltip: { trigger: "axis", }, areaStyle: { color: getColor(index, "area"), }, smooth: true, label: { show: true, //开启显示 position: "top", //在上方显示 //数值款式 color: getColor(index, "default"), fontSize: defaultLabelFontsize, }, };};// 获取柱形系列配置export const getBarSeriesOptions = (index) => { return { barWidth: 10, label: { show: true, //开启显示 position: "top", //在上方显示 //数值款式 color: getColor(index, "default"), fontSize: defaultLabelFontsize, }, itemStyle: { borderRadius: [6, 6, 0, 0], }, };};
Step-2: 新建一个index.vue文件
<!--/*** Author: 前端小高* Date: 2023-05-08 14:58* Desc: MyChart 文件形容*/--><template> <div ref="chartDom" class="chart-dom"></div></template><script name="MyChart" lang="ts" setup>import { ref, computed, watch, onMounted, onBeforeUnmount, PropType, nextTick } from "vue";import * as ECharts from "echarts";import { debounce } from "lodash";import { baseColorArr, chartDataType, chartOptionsType, chartSupportType, chartDataItemType, getLineBarBaseOptions, getLineSeriesOptions, getBarSeriesOptions, config,} from "./config";const props = defineProps({ color: { type: Array as PropType<string[]>, default: () => { return baseColorArr; }, }, // 超过该数字时显示滚动条 showZoomLimit: { type: Number, default: 7, }, // 坐标轴是否两边留白 isBoundaryGap: { type: Boolean, default: false, }, baseOptions: { type: Object as PropType<chartOptionsType>, default: () => { return {}; }, }, data: { type: Array as PropType<chartDataType[]>, require: true, },});const emits = defineEmits(["chart-click"]);const initSeriesData = () => { if (props?.data?.length) { getXAxisDataArr(); const tempSeriesArr = props?.data.map((item: chartDataType, index: number) => { const chartOptions = getSeriesItemOptions(item, index); return { name: item.name, data: getValueArr(item.data, item?.valueKey), type: item.type, ...chartOptions, }; }); const tempLegendDataArr = props?.data.map((item: chartDataType) => item.name); legendDataArr.value = tempLegendDataArr; seriesArr.value = tempSeriesArr; }};const getXAxisDataArr = () => { const labelName = props?.data?.[0]?.labelKey || config.labelKey; const xDataArr = props?.data?.[0]?.data.map((item) => item[labelName]); dataArr.value = xDataArr as string[];};const callbackMap = { line: getLineSeriesOptions, bar: getBarSeriesOptions,};const getSeriesItemDefaultOptions = (type: chartSupportType = "line") => { return callbackMap[type];};const getChartBaseOptions = () => { return getLineBarBaseOptions;};const getSeriesItemOptions = (chartItem: chartDataType, index = 0) => { const cb = getSeriesItemDefaultOptions(chartItem.type); const defaultOptions = cb(index); if (chartItem?.options) { const mergeOptions = Object.assign({}, defaultOptions, chartItem?.options); return mergeOptions; } else { return defaultOptions; }};const getBaseChartOptions = () => { const cb = getChartBaseOptions(); const baseOptions = cb(dataArr.value.length, props.showZoomLimit); if (props?.baseOptions) { const mergeOptions = Object.assign({}, baseOptions, props?.baseOptions); return mergeOptions; } else { return baseOptions; }};const getValueArr = (arr: chartDataItemType[], valueKey?: string) => { const keyName = valueKey ? valueKey : config.valueKey; return arr.map((item) => Number(item[keyName]));};const resizeHandler = () => { chartExample.resize();};const resizeHandlerOrigin = debounce(resizeHandler, 300);const dataArr = ref<any[]>([]);const seriesArr = ref<any[]>([]);const legendDataArr = ref<string[]>([]);const getOptions = computed(() => { const baseOptions = getBaseChartOptions(); const options = { color: props.color, ...baseOptions, legend: { data: legendDataArr.value, }, xAxis: { type: "category", data: dataArr.value, boundaryGap: props.isBoundaryGap, axisTick: { alignWithLabel: true, }, }, series: seriesArr.value, }; return options;});watch( () => props.data, () => { init(); }, { deep: true, });const chartDom = ref();let chartExample: any = null;const initChart = () => { if (chartExample) { // 若存在图表实例,则先执行销毁操作 chartExample.dispose(); } nextTick(() => { chartExample = ECharts.init(chartDom.value); const options = getOptions.value; chartExample.setOption(options, true); initResizerListener(); initChartEvent(); });};const initResizerListener = () => { window.removeEventListener("resize", resizeHandlerOrigin); window.addEventListener("resize", resizeHandlerOrigin);};const initChartEvent = () => { cancelClickEvent(); chartExample.on("click", (params) => { emits("chart-click", params); });};const cancelClickEvent = () => { chartExample.off("click");};const init = () => { initSeriesData(); initChart();};onMounted(() => { init();});onBeforeUnmount(() => { cancelClickEvent(); window.removeEventListener("resize", resizeHandlerOrigin); chartExample.dispose();});</script><style lang="scss" scoped>.chart-dom { height: 300px;}</style>
Step-3:页面下的援用形式
<!--/*** Author: 前端小高* Date: 2023-05-08 14:55* Desc: ChartComp 图表组件*/--><template> <my-chart :data="dataArr"></my-chart></template><script name="ChartComp" lang="ts" setup>import { ref } from "vue";import { chartDataType } from "@/common/MyChart/config";const dataArr = ref<chartDataType[]>([ { name: "测试数据列1", type: "line", data: [ { name: "1.1", value: 1, }, { name: "1.2", value: 2, }, { name: "1.3", value: 3, }, { name: "1.1", value: 1, }, ], },]);</script>
页面展现成果如下
代码Gitee地址
比照根底版本的echarts封装组件,2.0版本做了如下优化
- 只需传入渲染数据及展现数据类型,即可渲染
- 其余图表配置能够按需传入
- (不足之处:以后只做了折线图及柱形图的反对,其余类型图表各位能够按需扩大)