vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > Vue3自定义Echars组件附带全局配置

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插件

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>

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文