echarts 组件复用

echarts 组件复用

在前端开发过程中经常会遇到使用 echarts 报表的功能,有很多时候在一个页面或者是一个项目当中使用相同的 echarts 表,比如使用好几个柱状图、折线图之类的,而这些柱状图的样式是完全一样的,只是横纵坐标的数据不一样,因此我们可以将样式相同的 echarts 图表封装成一个组件,然后在需要使用的时候直接调用组件,传入x轴、y轴数据或者是其他的标题之类的数据就可以使用,不需要每个图表都单独创建一个组件去调用,从而减少代码量,提高组件复用性。

创建一个 bar 组件封装 echarts 报表

<template>
  <div style="width: 100%;height: calc(100% - 25px);">
    <div id="top" style="width: 100%;height:100%;"></div>
  </div>
</template>
<script>
  import echarts from 'echarts'
  // 引入改变窗口重新加载图表js。这个文件看之前的博客,有使用介绍
  import {
    
     EleResize } from '../../../../../../public/js/esresize.js'
  import 'echarts-gl'

  export default {
    
    
    name: '',
    props: ['showData'],
    data() {
    
    
      return {
    
    
        charts: '',
      }
    },
    watch: {
    
    
      showData() {
    
    
        this.$nextTick(function () {
    
    
          this.drawMap('top')
        })
      }
    },
    created() {
    
    
      this.$nextTick(function () {
    
    
        this.drawMap('top')
      })
    },
    methods: {
    
    
      drawMap(id) {
    
    
        let option = {
    
    
          color: ['#3398DB'],
          tooltip: {
    
    
            trigger: 'axis',
            axisPointer: {
    
                // 坐标轴指示器,坐标轴触发有效
              type: 'shadow'        // 默认为直线,可选为:'line' | 'shadow'
            }
          },
          grid: {
    
    
            left: '3%',
            right: '3%',
            bottom: '0%',
            top: '10%',
            containLabel: true
          },
          xAxis: [
            {
    
    
              type: 'category',
              boundaryGap: true,
              data: this.showData.xValue,
              axisTick: {
    
    
                show: false
              },
              axisLine: {
    
    
                lineStyle: {
    
    
                  color: "#9e9fa3",
                  width: 0,
                },
              },
            }
          ],
          yAxis: [
            {
    
    
              type: 'value',
              axisLabel: {
    
    
                margin: 15,
                formatter: "{value}",
                textStyle: {
    
    
                  color: "#9e9fa3",
                },
              },
              axisTick: {
    
    
                show: false
              },
              splitLine: {
    
    
                lineStyle: {
    
    
                  color: "#c8c9cb",
                  type: "dashed"
                },
              },
              axisLine: {
    
    
                show: false,
                lineStyle: {
    
    
                  color: "#9e9fa3",
                },
              },
            }
          ],
          series: [
            {
    
    
              name: '数据',
              type: 'bar',
              barWidth: '50%',
              data: this.showData.yValue
            }
          ]
        };

        this.charts = echarts.init(document.getElementById(id))
        // 改变屏幕大小图表重新加载
        var resizeDiv = document.getElementById(id)
        var listener = () => {
    
    
          this.charts.resize()
        }
        EleResize.on(resizeDiv, listener)
        this.charts.clear()
        this.charts.setOption(option)
      }
    },
    // 调用
    mounted() {
    
     },
    // 销毁
    destroyed() {
    
    
      // 销毁echarts图表
      this.charts.dispose()
    }
  }
</script>

如果单独每个echarts图表写一个vue组件按照上面就可以了。

showData是一个对象,里面有两个列表,xValue 是 x 轴数据,yValue 是 y 轴数据,然后放到相应的地方渲染就可以了。

留坑

但是这个组件是不可以复用的,如果有一个和这个图表样式相同的报表,再次调用传进 showData 数据会发现渲染不对,出问题,为什么,因为 echarts 渲染的时候,需要先创建一个 div 标签设置长宽渲染 echarts 图表,但是有一个问题,渲染的时候需要这个 div 有一个唯一的 id 值,这样的话,如果两个图表调用这同一个封装好的组件会有两个 id 相同的 div,因此会出现渲染问题。

填坑

这样的话,就需要在每次调用组件的时候,需要设置一个唯一 id 的 div 来渲染不同位置的 echarts 图表。

修改之前的代码:

<template>
  <div style="width: 100%;height: calc(100% - 25px);">
  	<!-- 假设有三个位置 top center bottom 需要渲染这个组件,需要创建三个div来渲染图表
  	     判断通过传进的id值,来判断渲染哪一个div -->
    <div id="top" style="width: 100%;height:100%;" v-if="id==='top'"></div>
    <div id="center" style="width: 100%; height: 100%;" v-if="id==='center'"></div>
    <div id="bottom" style="width: 100%; height: 100%;" v-if="id==='bottom'"></div>
  </div>
</template>
<script>
  import echarts from 'echarts'
  // 引入改变窗口重新加载图表js
  import {
    
     EleResize } from '../../../../../../public/js/esresize.js'
  import 'echarts-gl'

  export default {
    
    
    name: '',
    props: ['showData', 'id', 'unit'],  // showData是xy轴数据,id是div id值,unit是单位
    data() {
    
    
      return {
    
    
        charts: '',
      }
    },
    watch: {
    
    
      showData() {
    
    
        this.$nextTick(function () {
    
    
          switch (this.id) {
    
    
            case 'top':
              this.drawMap('top')
              break;
            case 'center':
              this.drawMap('center')
              break;
            case 'bottom':
              this.drawMap('bottom')
              break;
          }
        })
      }
    },
    created() {
    
    
      this.$nextTick(function () {
    
    
        switch (this.id) {
    
    
          case 'top':
            this.drawMap('top')
            break;
          case 'center':
            this.drawMap('center')
            break;
          case 'bottom':
            this.drawMap('bottom')
            break;
        }
      })
    },
    methods: {
    
    
      drawMap(id) {
    
    
        let option = {
    
    
          color: ['#3398DB'],
          tooltip: {
    
    
            trigger: 'axis',
            axisPointer: {
    
                // 坐标轴指示器,坐标轴触发有效
              type: 'shadow'        // 默认为直线,可选为:'line' | 'shadow'
            }
          },
          grid: {
    
    
            left: '3%',
            right: '3%',
            bottom: '0%',
            top: '10%',
            containLabel: true
          },
          xAxis: [
            {
    
    
              type: 'category',
              boundaryGap: true,
              data: this.showData.xValue,
              axisTick: {
    
    
                show: false
              },
              axisLine: {
    
    
                lineStyle: {
    
    
                  color: "#9e9fa3",
                  width: 0,
                },
              },
            }
          ],
          yAxis: [
            {
    
    
              type: 'value',
              axisLabel: {
    
    
                margin: 15,
                formatter: "{value}",
                textStyle: {
    
    
                  color: "#9e9fa3",
                },
              },
              axisTick: {
    
    
                show: false
              },
              splitLine: {
    
    
                lineStyle: {
    
    
                  color: "#c8c9cb",
                  type: "dashed"
                },
              },
              axisLine: {
    
    
                show: false,
                lineStyle: {
    
    
                  color: "#9e9fa3",
                },
              },
            }
          ],
          series: [
            {
    
    
              name: this.unit,
              type: 'bar',
              barWidth: '50%',
              data: this.showData.yValue
            }
          ]
        };

        this.charts = echarts.init(document.getElementById(id))
        // 改变屏幕大小图表重新加载
        var resizeDiv = document.getElementById(id)
        var listener = () => {
    
    
          this.charts.resize()
        }
        EleResize.on(resizeDiv, listener)
        this.charts.clear()
        this.charts.setOption(option)
      }
    },
    // 调用
    mounted() {
    
     },
    // 销毁
    destroyed() {
    
    
      // 销毁echarts图表
      this.charts.dispose()
    }
  }
</script>
<style scoped>
  * {
    
    
    margin: 0;
    padding: 0;
    list-style: none;
  }
</style> 

这样的话就可以在三个地方渲染这样的这个组件,但是如果有新位置也需要在加 div,也比每个图表创建一个 Vue 文件要方便许多,而且需要修改样式就可以修改这一个文件就可以了,不需要一个一个修改。

然后调用的时候:

<echart-bar :id="'center'" :showData="barCenter" :unit="'占比'"></echart-bar>
<echart-bar :id="'bottom'" :showData="bottomCenter" :unit="'数量'"></echart-bar>

图就暂时不截了…

优化

其实还有一个简单的方法,一直没说,因为上面基本上说的就是原理之类的解决方法,如果理解上面的骚操作,优化的方法不说估计也能想到。

提示: 传进来的 id 直接赋值给 div 的 id ,就不需要每次创建 div 设置唯一的 id 了 。

扫描二维码关注公众号,回复: 11976611 查看本文章

好了,可以点赞、关注、加评论了~ 哈哈哈哈!

猜你喜欢

转载自blog.csdn.net/weixin_42776111/article/details/109257545