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 了 。

還有別的辦法,ref ....

好了,可以點贊、關注、加評論了~ 哈哈哈哈!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM