顺便记录一下, vue 中 echarts 的使用 (感觉 echarts 不友好,都不说明按需引入里面各个组件代表什么意思)

一、问题

父子组件基本描述如下:

  • 父组件是容器组件,负责发送 HTTP 请求,向 API 请求数据,并将数据简单处理后,通过 props 传递给子组件
  • 子组件是基于 Echarts 的基本绘图组件,负责绘制某个图,算是一个 Base 组件

在实践的过程中,主要发现了问题:

由于父组件请求的数据并不是一成不变的,会根据不同的条件请求不同的数据,此时需要图表进行更新。

最早子组件基本结构如下:

  • loadingContainer 是因为我使用局部 loading 的时候容器组件,不需要关心
  • echarts 是通过局部引用的方式使用的,并不是全局引入
  • 子组件的 props:data/height/width/title/classes/

    • echarts 必须要求有 height 和 width
    • data 是相对应结构的图表驱动数据
    • title 和 classes 只是为了后面扩展使用的 标题和类名
  • 子组件的主要方法 :

    • _chart(): 图表绘制主要驱动方法(具体内容不需要关心,因为这个与业务逻辑有关)
    • _showLoading()_hideLoading() :用于加载 loading 和隐藏 loading 的方法
  • computed:styleObject 只是为了计算 style 对象(用 React 用多了)
  • mounted:挂载加载数据对象调用 chart
<template>
<div class="" ref="loadingContainer">
    <div :class="classes" ref = "chartContainer"  :style="styleObj" ></div>
</div>
<template>
<script>
  // 引入 echarts 基本模板
  let echarts = require('echarts/lib/echarts');
  // 引入图
  require('echarts/lib/chart/pie');
  // 引入提示框和标题组件
  require('echarts/lib/component/tooltip');
  require('echarts/lib/component/title');
  require('echarts/lib/component/legendScroll');
  export default {
    name: "char-pie",
    props:{
      data:{
        type:Array,
        required:true,
        default:[]
      },
      title:{
        type:String,
        default:'',
      },
      width:{
        type:String,
        default:"100px",
        required:true
      },
      height:{
        type:String,
        default:"100px",
        required:true
      },
      classes:{
        type:String,
        default:'',
        required:false
      }
    },
    mounted(){
      this._showLoading();
      this.$nextTick(()=>{
        if(this.data){
          this._chart();
        }
        this._hideLoading();
      });
    },
    computed:{
      styleObj(){
        return {
          width:this.width,
          height:this.height
        }
      }
    },
    methods:{
      /**
       * @name _chart
       * @description 图表绘制
       * @private
       */
      _chart(){
        let chart = echarts.init(this.$refs.chartContainer);
        const chartData = this.data;
        if(!chartData.length){
          return false;
        }
        // chart 的前三个数据需要判断是否是空
        const firstData = [];
        for(let i=0;i<3;i++){
          if(chartData[i]){
            firstData.push({value:chartData[i].value, name:chartData[i].name, selected:true});
          }
        }
        // 绘制图表
        chart.setOption({
          tooltip: {
            trigger: 'item',
            formatter: "{a} <br/>{b}: {c} ({d}%)"
          },
          series: [
            {
              name:'方式:人数',
              type:'pie',
              selectedMode: 'single',
              radius: [0, '30%'],

              label: {
                normal: {
                  position: 'inner'
                }
              },
              labelLine: {
                normal: {
                  show: false
                }
              },
              data:firstData
            },
            {
              type:'pie',
              radius: ['40%', '55%'],
              data:chartData
            }
          ]
        });
        // 隐藏loading
      },

      /**
       * @name _showLoading
       * @description todo(显示loading)
       * @private
       */
      _showLoading(){
        this._loadingObj = this.$loading({target:this.$refs.loadingContainer});
      },
      /**
       * @name _hideLoading
       * @description todo(隐藏loading)
       * @private
       */
      _hideLoading(){
        setTimeout(()=>{
         this._loadingObj.close();
        },1000);
      },
      beforeDestroy(){
        this._loadingObj = null;
      }
    }
  }

<script>

最开始,我只是在 mounted 阶段直接挂载了数据,但是后面发现,数据无法进行更改。

二、原因

自己当时没有想那么多为什么无法加载,因此在另一个父组件进行应用的时候,他是首屏就加载,数据不变动。

但是当数据变动之后,无法自动的更新图表。

由于 mounted 只会在挂载的时候执行一次,因此无法后续进行更新

三、解决

最后通过 watch data 进行图表的更新,添加的内容如下:

watch:{
      data(){
        this._showLoading();
        this.$nextTick(()=>{
          if(this.data){
            this._chart();
          }
          this._hideLoading();
        });
      }
    },