1

1、@vueuse/core 工具库

官网地址:https://vueuse.org/guide/#installation

概念:它是为Vue 2和3服务的一套Vue Composition API的常用工具集,是目前世界上Star最高的同类型库之一。它的初衷就是将一切原本并不支持响应式的JS API变得支持响应式,省去程序员自己写相关代码引用

2、引入lodash工具库

项目为ts,引用lodash-es 版本,以及ts版本
//lodash-unified为ts版
npm i lodash-es lodash-unified -S
npm i @types/lodash-es -D

//使用判断两个对象是否相等
import { isEqual } from 'lodash-unified';

3、按需引入echarts5以及封装

参考地址:https://echarts.apache.org/handbook/zh/get-started/
第一步:npm install echarts --save
第二步创建按需引入文件echarts/index.ts

import * as echarts from 'echarts/core';

//具体组件地址:\node_modules\echarts\lib\export\charts.js
import { PieChart, BarChart, LineChart } from 'echarts/charts';
import { SVGRenderer } from 'echarts/renderers';

//具体组件地址:\node_modules\echarts\lib\export\components.js
import {
  GridComponent,
  TitleComponent,
  LegendComponent,
  ToolboxComponent,
  TooltipComponent,
  DataZoomComponent,
  VisualMapComponent
} from 'echarts/components';

const { use, registerTheme } = echarts;

use([
  PieChart,
  BarChart,
  LineChart,
  SVGRenderer,
  GridComponent,
  TitleComponent,
  LegendComponent,
  ToolboxComponent,
  TooltipComponent,
  DataZoomComponent,
  VisualMapComponent
]);

// 自定义主题(可以修改theme.json添加一些默认的样式)
// 配置的格式可以参考这个下载下来的格式:https://echarts.apache.org/zh/theme-builder.html
import theme from './theme.json';
registerTheme('ovilia-green', theme);

export default echarts;

第三步:封装单个组件,比如bar柱状图

<template>
  <div ref="barRef" style="width: 100%; height: 100%"></div>
</template>

<script setup lang="ts">
// echarts ts 定义
import { EChartOption, ECharts } from 'echarts';
// 引入公共的echarts组件(按需实现)
import echarts from '@/plugin/echarts/index';
import { onBeforeMount, onMounted, nextTick, ref, watch } from 'vue';
import { useEventListener, tryOnUnmounted, useTimeoutFn } from '@vueuse/core';
import { isEqual } from 'lodash-unified';
//echarts实例
let echartInstance: ECharts | null;
interface optionProps {
  xdata: string[];
  seriesData: number[];
}
const props = withDefaults(
  defineProps<{
    option?: optionProps;
  }>(),
  {
    option: () => {
      return {
        xdata: ['aa', 'bb', 'cc', 'dd'],
        seriesData: [3, 204, 1079, 1079]
      };
    }
  }
);
let barRef = ref<HTMLElement | null>(null);
const options = {
  option: {
    tooltip: {
      trigger: 'axis',
      axisPointer: {
        type: 'shadow'
      }
    },
    grid: {
      bottom: '20%',
      height: '68%',
      containLabel: true
    },
    xAxis: [
      {
        type: 'category',
        axisTick: {
          alignWithLabel: true
        },
        axisLabel: {
          interval: 0
        },
        data: props.option && props.option.xdata
      }
    ],
    yAxis: [
      {
        type: 'value'
      }
    ],
    series: [
      {
        name: 'GitHub信息',
        type: 'bar',
        data: props.option && props.option.seriesData
      }
    ]
  }
};

function initEchartsInstance() {
  if (echartInstance != null && echartInstance != undefined) {
    echartInstance.dispose(); //解决echarts dom已经加载的报错
  }
  const echartsDom = barRef.value;
  if (!echartsDom) return;
  //@ts-ignore
  echartInstance = echarts.init(echartsDom);
  echartInstance?.clear(); //清除画布,重新渲染
  echartInstance?.setOption(options.option as EChartOption);
}
onBeforeMount(() => {
  nextTick(() => {
    initEchartsInstance();
  });
});
onMounted(() => {
  nextTick(() => {
    useEventListener('resize', () => {
      if (!echartInstance) return;
      useTimeoutFn(() => {
        echartInstance?.resize();
      }, 100);
    });
  });
});
// 监听入参有变化就重新刷新
watch(
  () => props.option,
  (newProps, oldProps) => {
    let flag: boolean = isEqual(newProps, oldProps);
    if (!flag) {
      nextTick(() => {
        options.option.xAxis[0].data = newProps.xdata;
        options.option.series[0].data = newProps.seriesData;
        initEchartsInstance();
      });
    }
  }
);

tryOnUnmounted(() => {
  if (!echartInstance) return;
  echartInstance.dispose();
  echartInstance = null;
});
</script>

<style scoped></style>

第四步:组件中使用

<template>
  <div class="test-bar">
    <ReBar />
  </div>
  <div class="test-bar">
    <ReBar :option="options.option" />
  </div>
</template>

<script setup lang="ts">
import ReBar from '@/components/echarts/ReBar.vue';
import { ref, onUnmounted, reactive } from 'vue';
let timer = ref<any>(null);
let options = reactive({
  option: {
    xdata: ['哈哈', '嘿嘿', '嘻嘻', '呵呵'],
    seriesData: [22, 33, 55, 88]
  }
});
timer.value = setInterval(() => {
  options.option = {
    xdata: ['哈哈', '嘿嘿', '嘻嘻', '呵呵'],
    seriesData: [123, 33, 11, 34]
  };
}, 3000);
onUnmounted(() => {
  if (timer.value) {
    clearInterval(timer.value);
    timer.value = null;
  }
});
</script>

<style lang="less" scoped>
.test-bar {
  width: 50%;
  height: 250px;
  overflow: hidden;
}
</style>

suipa
237 声望16 粉丝

前端程序猿