Vue + Element-ui實現后台管理系統(4)---封裝一個ECharts組件的一點思路


封裝一個ECharts組件的一點思路

有關后台管理系統之前寫過三遍博客,看這篇之前最好先看下這三篇博客。另外這里只展示關鍵部分代碼,項目代碼放在github上: mall-manage-system

1、Vue + Element-ui實現后台管理系統(1) --- 總述

2、Vue + Element-ui實現后台管理系統(2) --- 項目搭建 + ⾸⻚布局實現

3、Vue + Element-ui實現后台管理系統(3) --- 面包屑 + Tag標簽切換功能

這篇主要講解實現圖表的功能:

整體效果

一、封裝一個ECharts組件的一點思路

1、繪制一個簡單的圖表

ECharts上手非常簡單,具體簡單示例可以參考我之前寫的一篇博客:圖表工具--- ECharts.js學習(一) 簡單入門

2、封裝思路

在實際項目開發中,我們會經常與圖表打交道,比如 訂單數量表商品銷量表會員數量表等等,它可能是以折線圖柱狀圖餅狀圖等等的方式來展現。

如果我們沒有封裝組件的思想的話,那么我們每次需要畫一個圖表都要重復類似相同的工作,而且代碼看去非常冗余。所以我們就需要考慮封裝一個ECharts組件,這個組件通過接收

不同的數據來渲染成不同的圖表,以后當需要生成一張圖表的時候,只需要把相關的數據傳入到這個組件中,就會渲染對應的圖表。

而這里的核心就是 哪些數據是需要我們傳入組件中的。針對這個問題我們來看下一個ECharts最簡單的示例

  // 指定圖表的配置項和數據
        var option = {
            title: {
                text: 'ECharts 入門示例'
            },
            tooltip: {},
            legend: {
                data:['銷量']
            },
            xAxis: {
                data: ["襯衫","羊毛衫","雪紡衫","褲子","高跟鞋","襪子"]
            },
            yAxis: {},
            series: [{
                name: '銷量',
                type: 'bar',
                data: [5, 20, 36, 10, 10, 20]
            }]
        };

運行結果

這里展示了一個最簡單的圖表,官方例子地址:5 分鍾上手 ECharts,下面對這些參數做個講解

title : 標題

tooltip : 提示框組件

legend : 圖例組件

xAxis : 直角坐標軸中的 x 軸

yAxis : 直角坐標軸中的 y 軸

series : 系列列表。每個系列通過 type 決定自己的圖表類型

這幾個組件來看 seriesxAxis 是肯定需要外部傳來的數據,y軸 的數據跟series中data相關不需要單獨再傳。至於title , tooltip , legend並不是圖表必須的,所以

不是必須要傳的。就好比你一個圖表你可以沒有標題。

注意 這里還有一點 x軸對於柱狀圖、折線圖相關圖是一定要有的,但對於餅狀圖來講它又不是必須的,所以這里封裝一個ECharts組件時,需要考慮這一點。

3、封裝ECharts組件

新建一個EChart.vue,作為封裝ECharts的組件

<template>
  <!--圖表展示在這個div中-->
  <div style="height: 100%" ref="echart">
    echart
  </div>
</template>

<script>
import echarts from 'echarts'
export default {
  //接收父類兩個數據 1、chartData (series數據 + x坐標系數據)2、isAxisChart (是否有x坐標系,如果false,那么上面的xData就為空)
  props: {
    chartData: {
      type: Object,
      default() {
        return {
          xData: [],
          series: []
        }
      }
    },
    isAxisChart: {
    //默認type為true 就代表默認是有x軸的
      type: Boolean,
      default: true
    }
  },
  computed: {
    //計算 選擇是有x軸 還是沒有x軸的數據
    options() {
      return this.isAxisChart ? this.axisOption : this.normalOption
    },
    //用於下面的resize 改變圖表尺寸,在容器大小發生改變時需要手動調用
    isCollapse() {
      return this.$store.state.tab.isCollapse
    }
  },
  watch: {
    //監聽chartData數據
    chartData: {
      handler: function() {
        this.initChart()
      },
      deep: true
    },
    //監聽isCollapse 因為頭部水平擴展是一個動畫需要時間,所以這里延遲300毫秒
    isCollapse() {
      setTimeout(() => {
        this.resizeChart()
      }, 300)
    }
  },
  data() {
    //在數據中有些數據在數據件中是寫死的
    return {
      echart: null,
      axisOption: {
        legend: {
          textStyle: {
            color: '#333'
          }
        },
        grid: {
          left: '20%'
        },
        tooltip: {
          trigger: 'axis'
        },
        xAxis: {
          type: 'category',
          data: [],
          axisLine: {
            lineStyle: {
              color: '#17b3a3'
            }
          },
          axisLabel: {
            color: '#333'
          }
        },
        yAxis: [
          {
            type: 'value',
            axisLine: {
              lineStyle: {
                color: '#17b3a3'
              }
            }
          }
        ],
        color: [
          '#2ec7c9',
          '#b6a2de',
          '#5ab1ef',
          '#ffb980',
          '#d87a80',
          '#8d98b3',
          '#e5cf0d',
          '#97b552',
          '#95706d',
          '#dc69aa',
          '#07a2a4',
          '#9a7fd1',
          '#588dd5'
        ],
        series: []
      },
      normalOption: {
        tooltip: {
          trigger: 'item'
        },
        color: ['#0f78f4', '#dd536b', '#9462e5', '#a6a6a6', '#e1bb22', '#39c362', '#3ed1cf'],
        series: []
      }
    }
  },
  methods: {
    initChart() {
      //獲取處理好的數據
      this.initChartData()
      //獲取echart對象
      if (this.echart) {
        this.echart.setOption(this.options)
      } else {
        //通過refs獲取
        this.echart = echarts.init(this.$refs.echart)
        this.echart.setOption(this.options)
      }
    },
    //處理好數據
    initChartData() {
      if (this.isAxisChart) {
        this.axisOption.xAxis.data = this.chartData.xData
        this.axisOption.series = this.chartData.series
      } else {
        this.normalOption.series = this.chartData.series
      }
    },
    resizeChart() {
      this.echart ? this.echart.resize() : ''
    }
  },
  mounted() {
    //resize 改變圖表尺寸,在容器大小發生改變時需要手動調用(因為側邊欄是可以收縮的,所以這里圖表根據是否收縮來改變圖表尺寸)
    window.addEventListener('resize', this.resizeChart)
  },
  //銷毀 防止內存泄漏
  destroyed() {
    window.removeEventListener('resize', this.resizeChart)
  }
}
</script>

<style lang="scss" scoped></style>

這樣一個簡單的公共組件就完成了,接下來我們通過傳入不同的數據到這個組件來渲染不同的圖表。


二、傳入EChart組件數據

我們看到在首頁有三個圖表,那我們這里就要組裝三種不同的數據,傳入到EChart.vue組件中,來生成不同的圖表。

<template>
   <div>
       <!--圖表一 這里的數據是折線圖-->
    <echart style="height: 280px" :chartData="echartData.order"></echart>
       <!--圖表二 這里的數據是柱狀圖-->
    <echart :chartData="echartData.user" style="height: 260px"></echart>
       <!--圖表三 這里的數據是餅狀圖 因為餅狀圖是不用x軸的 所以這里isAxisChart為false-->
    <echart :chartData="echartData.video" style="height: 260px" :isAxisChart="false"> 
    </div>
</template>

<script>
import Echart from '../../components/EChart'
export default {
  components: {
    Echart
  },
  data() {
    return {
      echartData: {
        //圖一
        order: {
          xData: [],
          series: []
        },
        //圖二
        user: {
          xData: [],
          series: []
        },
        //圖三 餅狀圖沒有x軸
        mall: {
          series: []
        }
      }
    }
  },
  methods: {
    getTableData() {
      this.$http.get('/home/getData').then(res => {
        res = res.data
        // 訂單折線圖
        const order = res.data.orderData
        //x軸數據 為日前
        this.echartData.order.xData = order.date
        // 第一步取出series中的name部分——小米,三星、蘋果...
        let keyArray = Object.keys(order.data[0])
        // 第二步,循環添加數據
        keyArray.forEach(key => {
          this.echartData.order.series.push({
            //如果有需要還可以做一步抓換比如:后台返回性別是1、2。那這里key === 1 ? '男' : 女,
            name: key === 'wechat' ? '小程序' : key,
            data: order.data.map(item => item[key]),
            type: 'line'
          })
        })
        // 用戶柱狀圖
        this.echartData.user.xData = res.data.userData.map(item => item.date)
        this.echartData.user.series.push({
          name: '新增用戶',
          data: res.data.userData.map(item => item.new),
          type: 'bar'
        })
        this.echartData.user.series.push({
          name: '活躍用戶',
          data: res.data.userData.map(item => item.active),
          type: 'bar',
          barGap: 0
        })
        // 商品餅圖
        this.echartData.mall.series.push({
          data: res.data.mallData,
          type: 'pie'
        })
      })
    }
  },
  created() {
    this.getTableData()
  }
}
</script>

大致的思路就是這樣的,如果你想在組件中加入title等參數,那也可以修改下這個組件就可以了。

總結下封裝組件的基本思路

1、觀察⽂檔,考慮組件需要的基本參數
2、參數篩選,分為從⽗組件傳來的參數和⾃身的參數
3、完善組件,觀察設計圖,找不同,在⽂檔中尋找對應的配置項
4、細節優化,考慮多種場景下,圖表⾃適應的處理


別人罵我胖,我會生氣,因為我心里承認了我胖。別人說我矮,我就會覺得好笑,因為我心里知道我不可能矮。這就是我們為什么會對別人的攻擊生氣。
攻我盾者,乃我內心之矛(14)


免責聲明!

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



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