Vue:在Vue中使用echarts

前言

公司的項(xiàng)目中需要對(duì)數(shù)據(jù)做可視化處理,高級(jí)點(diǎn)的D3.js目前還沒(méi)接觸到,因此選用了大眾化的Echarts, 在vue的生態(tài)系統(tǒng)中已經(jīng)有實(shí)現(xiàn)好的vue-echarts,但是使用現(xiàn)成的就意味著必須使用它定制好的數(shù)據(jù)結(jié)構(gòu),我也沒(méi)辦法對(duì)他進(jìn)行一些修改。我個(gè)人也偏向于原生JS編程,因此沒(méi)有采用,而是自己在vue中實(shí)現(xiàn)了對(duì)數(shù)據(jù)的可視化處理,先來(lái)看看效果圖

以下數(shù)據(jù)已做脫敏處理

echarts Bar.png
echartsPie.png
echartsMap.png

這是目前用到的三種圖。
可以看到,我在圖表的外部添加了標(biāo)題及說(shuō)明,以及右側(cè)的選擇框組件,視圖可以根據(jù)選擇的不同,圖表進(jìn)行動(dòng)態(tài)切換(echarts也是數(shù)據(jù)驅(qū)動(dòng)),這就是個(gè)人定制化的好處

總體數(shù)據(jù)流向

所有的數(shù)據(jù)都是動(dòng)態(tài)獲取的,由前端向后臺(tái)請(qǐng)求。當(dāng)然請(qǐng)求數(shù)據(jù)肯定不會(huì)放在圖表組件中,而是放在了外部。因?yàn)榧軜?gòu)設(shè)計(jì)的不合理(MD前端就我一個(gè)人!),因此前期獲取數(shù)據(jù)及存取數(shù)據(jù)的方式,和后期也較大的不同。

1. 存放在vuex中

這么大型的項(xiàng)目,vuex少不了。在前面的組件中,一次請(qǐng)求數(shù)據(jù),然后將數(shù)據(jù)存儲(chǔ)到了vuex中,echarts組件再?gòu)膙uex中獲取數(shù)據(jù)。這樣的做法可能代碼要稍微復(fù)雜點(diǎn),但是數(shù)據(jù)存儲(chǔ)在vuex中是隨時(shí)可見(jiàn)的,我們也能隨時(shí)保存獲取的結(jié)果,對(duì)這些數(shù)據(jù)可以添加收藏也可以加入緩存中,下次再請(qǐng)求可以先從緩存調(diào)用。
(然而這只是我前端的想法,后臺(tái)已經(jīng)實(shí)現(xiàn)了對(duì)請(qǐng)求數(shù)據(jù)的緩存)

2. 存放在組件中,再分派到echarts組件

再對(duì)數(shù)據(jù)進(jìn)行還原的時(shí)候(我的收藏,最近瀏覽),因?yàn)椴恍枰4婊蛘呤詹財(cái)?shù)據(jù),我就直接用一個(gè)父組件請(qǐng)求,然后再分發(fā)到echarts組件,這樣沒(méi)有經(jīng)過(guò)vuex,代碼想多要少些。

組件代碼

<template>
  <div class="r-echarts-line">
    <div class="top">
      <div class="title">
        {{origin.title}}
      </div>
      <div class="select-list">
        <Select style="width:120px;margin-right:.5rem" v-model="pagePick">
          <Option v-for="item in origin.page_select" :key="item" :value="item.val">{{item.name}}</Option>
        </Select>
        <Select style="width:120px" v-model="typePick">
          <Option v-for="item in typeList" :value="item.name" :key="item">{{item.name}}</Option>
        </Select>
      </div>
    </div>
    <div class="des">說(shuō)明:符合于本次篩選條件的共有<span class='tips'>{{origin.desc}}</span>條<span style="font-weight:700;color:black">職位信息</span>。</div>
    <div class="bottom" id="echart" ref="mychart">

    </div>
  </div>
</template>

這是組件的html部分,可以看見(jiàn)top以及des是我自己添加的,bottom才是核心,也是整個(gè)echarts展示的部分,注意這里添加了ref,在script的代碼中,我們將通過(guò)這個(gè)鉤子,將DOM掛載到echarts中

<script>
// echarts相關(guān)
let echarts = require('echarts/lib/echarts');
require('echarts/lib/chart/bar');
require('echarts/lib/component/tooltip');
require('echarts/lib/component/toolbox');
require('echarts/lib/component/legend');
require('echarts/lib/component/markLine');

export default {
  name: 'r-echarts-line',
  data () {
    return {
    typePick: '數(shù)值',
    typeList: [
      {
        name: '數(shù)值'
      },
      {
        name: '百分比'
      }
    ],
    pagePick: 0,
    // myChart實(shí)例
      myChart: {},
      percent: {
        label: {
          normal: {
            show: true,
            position: 'inside',
            formatter: '{c}%'
          }
        }
      },
      numeric: {
        label: {
          normal: {
            show: true,
            position: 'inside',
            formatter: '{c}'
          }
        }
      }
    }
  },
  props: {
    index: {
      required: true,
      type: Number
    },
    data: {
      required: true,
      type: Object
    }
  },
  mounted () {
    this.setEchart();
  },
  updated () {
    if (!this.myChart) {
      this.setEchart();
    }
    this.chartChange();
  },
  computed: {
    origin () {
      return this.data;
    },
    opt() {
      let that = this;
      let obj = {
        color: ['#606c94'],
        tooltip: {
        },
        toolbox: {
            show: true,
            feature: {
                saveAsImage: {show: true}
            }
        },
        label: {
          normal: {
            show: true,
            position: 'inside',
            formatter: '{c}'
          },
          emphasis: {
            show: true
          }
        },
        xAxis: {
          type: 'value',
        },
        yAxis: {
          data: that.origin[that.type][that.pagePick].key,
          axisLabel: {
            interval: 0,
            rotate: -30
          }
        },
        series: [{
          name: that.origin.title,
          type: 'bar',
          data: that.origin[that.type][that.pagePick].val,
          barMaxWidth: '30',
          markLine: {
            data: [
              {type: 'average', name: '平均值'}
            ]
          }
        }]
      }
      return obj;
    },
    type () {
      if (this.typePick == '數(shù)值') {
        return 'numeric';
      } else if (this.typePick == '百分比') {
        return 'percent';
      } else {
        return 'numeric';
      }
    }
  },
  methods: {
    setEchart () {
      let dom = this.$refs.mychart;
      this.myChart = echarts.init(dom);
      this.myChart.setOption(this.opt);
    },
    chartChange () {
      this.myChart.setOption(this.opt);
      if (this.typePick == '百分比') {
        this.myChart.setOption(this.percent);
      }
      if (this.typePick == '數(shù)值') {
        this.myChart.setOption(this.numeric);
      }
    }
  }
}
</script>

首先我引入了需要的echarts組件,這個(gè)部分通過(guò)npm i echarts -S添加。
接著data部分我設(shè)置了那些將會(huì)引起變化的參數(shù)。需要注意的是,我并沒(méi)有將echarts的opt部分寫(xiě)入到data中,因?yàn)?code>整個(gè)圖表是基于數(shù)據(jù)驅(qū)動(dòng)的,并且隨時(shí)會(huì)發(fā)生變化,因此我將opt設(shè)置為計(jì)算屬性computed,這樣opt將會(huì)根據(jù)我的選擇動(dòng)態(tài)變化,echarts也將動(dòng)態(tài)響應(yīng),mychart用于接收echarts生成的圖表實(shí)例,再參數(shù)變換的時(shí)候?qū)?huì)起作用。

props部分是我接收到的參數(shù),這個(gè)組件時(shí)基于前面我講的第二種方式——父組件獲取數(shù)據(jù)分發(fā),data是父組件分發(fā)給echarts的數(shù)據(jù)源。

暫時(shí)忽略兩個(gè)Vue生命周期鉤子, 后面講

計(jì)算屬性中設(shè)置了兩個(gè)屬性,origin和opt,注意這個(gè)origin很重要,通過(guò)它我將opt項(xiàng)與復(fù)雜的數(shù)據(jù)解耦,無(wú)論外面的數(shù)據(jù)怎么換,opt只關(guān)心origin的值,而這個(gè)opt在兩種數(shù)據(jù)獲取的方式中是不一樣的,使用vuex的方式,origin將會(huì)直接從vuex中獲取數(shù)據(jù)。這樣一定程度上也實(shí)現(xiàn)了組件的復(fù)用。
opt就是該圖表組件的設(shè)置項(xiàng)了,這個(gè)參數(shù)按照官網(wǎng)給的配置,自己搭配即可。

接下來(lái)是methods部分,setEchart將會(huì)完成對(duì)整個(gè)圖表的初始化,通過(guò)this.$refs獲取DOM實(shí)例,再由echars生成實(shí)例并綁定在data中的mychart選項(xiàng)。
chartChange是用來(lái)響應(yīng)我自定義組件的變化的,針對(duì)選框的不同將會(huì)有不同的顯示情況。在這里是百分比和數(shù)據(jù)的切換

接著是前面忽略的生命周期部分
mounted里使用setEchart方法,初始化圖表組件,一定要在這里使用該方法,否則會(huì)找不到DOM

updated周期里是響應(yīng)參數(shù)變化的方法,首先檢測(cè)該實(shí)例有沒(méi)有生成(單頁(yè)應(yīng)用因?yàn)橛脩艨赡艽嬖诘恼`操作,很可能導(dǎo)致實(shí)例沒(méi)有生成,這里檢測(cè)是很有必要的),接著在vue中的數(shù)據(jù)發(fā)生改變時(shí)運(yùn)行chartChange方法,注意,我的選擇框是沒(méi)有綁定事件的,只是通過(guò)v-model改變了參數(shù),然后opt動(dòng)態(tài)響應(yīng)了參數(shù)的變化。當(dāng)opt的參數(shù)變化的時(shí)候,updated中的方法就會(huì)執(zhí)行,echarts也會(huì)動(dòng)態(tài)響應(yīng)。這個(gè)就是使用基于數(shù)據(jù)驅(qū)動(dòng)vue最精巧的地方,避免了通過(guò)事件調(diào)用echartChange方法。也是vue中使用echarts核心的一環(huán)

另外還有一個(gè)就是獲取地圖參數(shù)的,并不用在官網(wǎng)里下載,提供的npm包里就有,按需引用就好了(使用官網(wǎng)的js版本會(huì)報(bào)錯(cuò)沒(méi)找到echarts)

import echarts from 'echarts/lib/echarts';
import 'echarts/lib/chart/map';
import 'echarts/map/js/china.js';

style部分就沒(méi)什么好聊的了,只需要記住一點(diǎn),必須顯式指定加載echarts 的DOM的寬度和高度

父組件對(duì)echarts組件的調(diào)用

調(diào)用組件的方法按照常規(guī)組件調(diào)用就好了,只是因?yàn)閑charts加載數(shù)據(jù)繪制需要耗費(fèi)不少時(shí)間,我們可能需要通過(guò)keep-alive保存組件在內(nèi)存中,避免切出去的時(shí)候被釋放了。另外可能一個(gè)頁(yè)面需要展示多個(gè)echarts類型組件,這里考慮使用component動(dòng)態(tài)組件

<template>
  <div class="focus-echarts-wrap">
    <keep-alive>
      <component :is="currentView" :index="focusType"></component>
    </keep-alive>
  </div>
</template>

其他問(wèn)題

在生成柱狀圖和餅狀圖的時(shí)候,加載時(shí)間并不算太慢。只是在加載地圖類型的時(shí)候,尤其是我在生成中國(guó)地圖的時(shí)候,達(dá)到了10s+的延遲,并且阻塞的是主線程,這段時(shí)間用戶是無(wú)法操作的,相當(dāng)于卡頓的情況。
該數(shù)據(jù)是在32bit的QQ瀏覽器上測(cè)得的,同事用的64bit的谷歌瀏覽器會(huì)好一點(diǎn)。

初步判斷是echarts的問(wèn)題。當(dāng)然也因?yàn)槭窃赿ev模式下,可能和我打開(kāi)了vuex和事件的監(jiān)測(cè)有關(guān)。具體的延遲時(shí)間我會(huì)在線上版本測(cè)試,希望情況會(huì)好轉(zhuǎn)吧,不然BOSS又要。。。。。。。。

就是這樣:)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 來(lái)源:github.com Vue.js開(kāi)源項(xiàng)目速查表:https://www.ctolib.com/cheats...
    zhangtaiwei閱讀 11,651評(píng)論 1 159
  • UI組件element ★11612 - 餓了么出品的Vue2的web UI工具套件 Vux ★7503 - 基于...
    董董董董董董董董董大笨蛋閱讀 8,560評(píng)論 6 123
  • #從零開(kāi)始學(xué)習(xí)寫(xiě)作#17斷舍離就只是扔扔扔? 隨著日本山下英子“斷舍離”概念的風(fēng)行,整理術(shù)、極簡(jiǎn)主義變得有些泛濫。...
    歡仔熊閱讀 588評(píng)論 2 5
  • 心里空空的 若有似無(wú)的戀情 一個(gè)人和兩只貓的相處 寡淡的情感連結(jié) 孤身一人的異鄉(xiāng) 想放肆又不敢放肆 想做不一樣的自...
    Lomemo閱讀 158評(píng)論 0 0