在vue中通过Echarts封装图表组件

一、需求问题

在开发vue的项目中,我们可能会遇到这样的需求。我们需要去封装一个图表组件,然后这个图表组件在多个不同的页面中都是可以使用的。下面也就是我所封装的图表组件Chart,可以去实现复用。

二、需求分析

我们需要先引用echarts,初始化图表,设置配置项,进行渲染,监视传入的option参数,如果有变化则重新设置配置项,这样一个图表组件就已经封装好了。在其它页面当中,进行图表组件的引入。option合并传入的数据,返回一个 echarts 的 配置项,在组件装载前进行数据的请求。

三、需求实现

1. 封装Chart图表组件

<template>  
   <div class="default-chart" :style="{width, height}"></div>
</template>

<script>
import * as echarts from 'echarts/lib/echarts';
import 'zrender/lib/svg/svg';
// 引入提示框和标题组件

import throttle from '../../utils/throttle';

export default {
   name: 'basic-echarts',
   props: { // 规范传入参数格式,以及默认值
      renderer: {
         type: String,
         required: false
      },
      option: {
         type: Object,
         default: () => ({})
      },
      notMerge: {
         type: Boolean,
         default: false
      },
      lazyUpdate: {
         type: Boolean,
         default: false
      }
   },
   data() {
      return {
         chart: null,
         width: '100%',
         height: '100%'
      };
   },
   methods: {
      // 初始化图表
      initChart(el) {
         // renderer 用于配置渲染方式 可以是 svg 或者 canvas
         const renderer = this.renderer || 'canvas';
         console.log(renderer);
         this.chart = echarts.init(el, null, {
            renderer,
            width: 'auto',
            height: 'auto'
         });
      },
      // 设置配置项
      setOption(option) {
         if (!this.chart) {
            return;
         }

         const notMerge = this.notMerge;
         const lazyUpdate = this.lazyUpdate;

         this.chart.setOption(option, notMerge, lazyUpdate);
      },
      // 销毁
      dispose() {
         if (!this.chart) {
            return;
         }

         this.chart.dispose();
         this.chart = null;
      },
      // 重新渲染
      resize() {
         this.chart && this.chart.resize();
      },
      getInstance() {
         return this.chart;
      }
   },
   mounted() {
      this.$nextTick(function() {
         console.log('did mount');
         this.initChart(this.$el);
         this.setOption(this.option);
         window.addEventListener('resize', throttle(this.resize, 100));
      });
   },
   beforeDestroy() {
      this.dispose();
   },
   watch: {
      // 监视传入的 option 参数,如果有变化则重新设置配置项
      option(newOpt) {
         console.log('update config');
         this.setOption(newOpt);
      }
   }
};
</script>

<style lang="scss" scoped>
@import '../../scss/_common.scss';
</style>
  1. 其它页面引用图表组件
<!-- ECharts -- Radar -- 雷达图  -->
<template>
   <Chart :renderer="renderer" :option="option"/>
</template>

<script>
import { mapActions, mapState } from 'vuex';
// 引入当前图表配置需要用到的图表、组件
import 'echarts/lib/component/tooltip';
import 'echarts/lib/component/title';
import 'echarts/lib/component/grid';
import 'echarts/lib/component/legend';
import 'echarts/lib/chart/radar';
import 'echarts/map/js/china';
import Chart from '../components/Charts/index';

const colors = [
   '#bcd3bb',
   '#e88f70',
   '#edc1a5',
   '#9dc5c8',
   '#e1e8c8',
   '#7b7c68',
   '#e5b5b5',
   '#f0b489',
   '#928ea8',
   '#bda29a'
];

export default {
   name: 'echarts-radar',
   data() {
      return { renderer: 'canvas' };
   },
   computed: {
      ...mapState('charts', { currentData: 'radar' }),
      provinces() {
         const currentData = this.currentData || [];

         return currentData.map(data => data.province);
      },
      // option 合并传入的数据,返回一个 echarts 的 配置项
      option() {
         return {
            backgroundColor: '#161627',
            title: {
               text: 'AQI - 雷达图',
               left: 'center',
               textStyle: {
                  color: '#eee'
               }
            },
            legend: {
               bottom: 5,
               data: this.provinces,
               itemGap: 20,
               textStyle: {
                  color: '#fff',
                  fontSize: 14
               },
               selectedMode: 'single'
            },
            radar: {
               indicator: [
                  // 雷达图指示器
                  { name: 'AQI', max: 200 },
                  { name: 'PM2.5', max: 250 },
                  { name: 'PM10', max: 250 },
                  { name: 'CO', max: 5 },
                  { name: 'NO2', max: 150 },
                  { name: 'SO2', max: 120 }
               ],
               shape: 'circle', // 形状
               splitNumber: 5, // 分割段数
               splitLine: {
                  // 分隔线
                  lineStyle: {
                     color: [
                        'rgba(238, 197, 102, 0.1)',
                        'rgba(238, 197, 102, 0.2)',
                        'rgba(238, 197, 102, 0.4)',
                        'rgba(238, 197, 102, 0.6)',
                        'rgba(238, 197, 102, 0.8)',
                        'rgba(238, 197, 102, 1)'
                     ].reverse()
                  }
               },
               splitArea: {
                  // 分割区域
                  show: false
               },
               axisLine: {
                  // 坐标轴轴线
                  lineStyle: {
                     color: 'rgba(238, 197, 102, 0.5)'
                  }
               }
            },
            series: this.provinces.map((province, idx) => {
               return {
                  name: province,
                  type: 'radar',
                  lineStyle: {
                     width: 1,
                     opacity: 0.5
                  },
                  data: this.currentData[idx].data,
                  symbol: 'none',
                  itemStyle: {
                     color: colors[idx % colors.length]
                  },
                  areaStyle: {
                     opacity: 0.05
                  }
               };
            })
         };
      }
   },
   methods: {
      ...mapActions('charts', ['changeData'])
   },
   // 组件装载前请求数据
   async beforeMount() {
      const path = '/radar';
      const key = 'radar';

      await this.changeData({ path, key });
   },
   components: { Chart }
};
</script>

<style lang="scss" scoped>
@import '../scss/_common.scss';
</style>

发布了146 篇原创文章 · 获赞 34 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/weixin_42614080/article/details/103745057