Vue中如何封装一个公用的echarts组件

2,027 阅读1分钟

一、环境介绍

工欲善其事必先利其器,所以先介绍环境和依赖,让你少吃版本的亏。

环境

  • vue版本 2.6+
  • echarts版本 4.2.1 依赖安装:
  • npm install echarts resize-detector lodash -S

二、如何一步步的进行封装

  1. 我们首先得有一个echarts实例吧,先通过init()方法初始化;既然是公共组件,那么在组件中我们不需要关心业务,所以把option采用动态传入的方式;一个页面多处使用echarts,id相同,感觉不太舒服的样子,id也动态传入吧
<template>
  <div :ref="id" />
</template>
<script>
import echarts from 'echarts'
export default {
  props: {
    // 动态option
    option: {
      type: Object,
      default: () => {}
    },
    // id,赋予一个默认值,那么我们不传id也是可以的
    id: {
      type: String,
      default: 'chartDom'
    }
  },
  data() {
    return {
    }
  },
  mounted() {
    this.renderCharts()
  },
  methods: {
    // 初始化echarts
    renderCharts() {
      this.chart = echarts.init(this.$refs[this.id])
      if (this.option) {
        this.chart.setOption(this.option)
      }
    }
  }
}
</script>
  1. 到这里,我们组件其实就已经可以使用了,基本的轮廓有了,下面继续添枝加叶。当我们缩放屏幕的时候,这时的图表可不会自动缩放啥的。好的,不卖关子了,当容器大小改变时,应该去调用resize()函数,改变图表尺寸,屏幕缩放,防抖节流得考虑吧,为了省事,直接用loadsh吧。
// 监听元素大小(尺寸)变化
import { addListener, removeListener } from 'resize-detector'
// 防抖
import debounce from 'lodash/debounce'
  created() {
    this.resizefn = debounce(this.resize, 300)
  },
  mounted() {
    this.renderCharts()
    // 新增,监听元素尺寸变化
    addListener(this.$refs[this.id], this.resizefn)
  },
   methods: {
    // resize()函数
    resize() {
      this.chart.resize()
    }
   }
  1. 下面来进行优化,比如在beforeDestroy中移除监听器,销毁echarts实例等;当然我们还需要监听option,当option变化时,重新setOption()
 watch: {
   option: {
     handler(val) {
       this.chart.setOption(this.option)
     },
     deep: true
   }
 },
 beforeDestroy() {
   // 移除监听器
   removeListener(this.$refs[this.id], this.resizefn)
   // 销毁echarts实例
   this.chart.dispose()
   this.chart = null
 },
 methods: {
   renderCharts() {
     this.chart = echarts.init(this.$refs[this.id])
     if (this.option) {
       this.chart.setOption(this.option)
     }
     const _this = this
     // 注册点击事件
     this.chart.on('click', function(params) {
       _this.$emit('onClick', params)
     })
   }
 } 

三、完整代码及使用

完整代码
<template>
  <div :ref="id" />
</template>
<script>
import echarts from 'echarts'
// 监听元素大小(尺寸)变化
import { addListener, removeListener } from 'resize-detector'
// 防抖
import debounce from 'lodash/debounce'
export default {
  props: {
    option: {
      type: Object,
      default: () => {}
    },
    id: {
      type: String,
      default: 'chartDom'
    }
  },
  data() {
    return {
    }
  },
  watch: {
    option: {
      handler(val) {
        this.chart.setOption(this.option)
      },
      deep: true
    }
  },
  created() {
    // 防抖,性能优化
    this.resizefn = debounce(this.resize, 300)
  },
  mounted() {
    this.renderCharts()
    // 监听元素尺寸变化
    addListener(this.$refs[this.id], this.resizefn)
  },
  beforeDestroy() {
    // 移除监听器
    removeListener(this.$refs[this.id], this.resizefn)
    // 销毁echarts实例
    this.chart.dispose()
    this.chart = null
  },
  methods: {
    resize() {
      this.chart.resize()
    },
    // 初始化
    renderCharts() {
      this.chart = echarts.init(this.$refs[this.id])
      if (this.option) {
        this.chart.setOption(this.option)
      }
      const _this = this
      // 注册点击事件
      this.chart.on('click', function(params) {
        _this.$emit('onClick', params)
      })
    }
  }
}
</script>
使用
<template>
  <div>
    <h5 style="text-align:center;">echarts图表的封装</h5>
    <Charts v-if="chartOption" :option="chartOption" style="height:600px;"></Charts>
  </div>
</template>
<script>
import Charts from './components/Charts'
export default {
  components: {
    Charts
  },
  data() {
    return {
      chartOption: null
    }
  },
  created() {
    this.getChartsData()
  },
  methods: {
    getChartsData() {
      setTimeout(() => {
        this.chartOption = {
          title: {
            text: '疯狂测试'
          },
          tooltip: {
            trigger: 'item'
          },
          xAxis: {
            data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
          },
          yAxis: {},
          series: [{
            name: '销量',
            type: 'pie',
            data: [100, 150, 50, 200, 120, 300]
          }]
        }
      }, 1000)
    }
  }
}
</script>