微信小程序使用echarts实现动态更新数据、以及echarts使用懒加载

6,246 阅读7分钟

每天都在入门,每天都未入门的前端小白---就是我!

本文主要记录了微信小程序如何使用echarts图表,包括初始化echart图表、使用echarts懒加载、以及如何实现echarts动态改变数据源。

好了,话不多说,直接说如何使用echarts吧

echarts的github上下载ec-canvas文件夹,放在项目的components文件夹中,在app.json中引入:

"usingComponents": {
    "mp-icon": "weui-miniprogram/icon/icon",
    "ec-canvas": "./components/ec-canvas/ec-canvas"
  },

静态echarts图

静态echart的使用可以直接下载官方提供的项目直接模仿着使用即可,这部分的介绍比较简单,可以直接跳过。

  • 在模板文件中使用ec-canvas组件:
<!--pages/bar/bar.wxml-->
<view class="echartBox">
  <ec-canvas id="mychart-dom-bar" canvas-id="mychart-bar" ec="{{ bar }}"></ec-canvas>
</view>

注意: 这里需要保证echartBox类是有宽度和高度的。否则会导致图表不能正常显示,只显示空白。

其中 ec 是一个需要在 bar.js 中定义的对象,它使得图表能够在页面加载后被初始化并设置。

  • 在逻辑文件中引入echarts: import * as echarts from '../../conn/ec-canvas/echarts';, 初始化图表:
// pages/bar/bar.js
import * as echarts from '../../conn/ec-canvas/echarts';
let chart = null;
let barOneData = {
  xData: [1,2, 3, 4, 5, 6, 7,8,9,10,11,12],
  sData: [100, 110, 113, 126, 143, 158, 165,167,152,102,,]
}
var barOneOption = {
  tooltip: {
    trigger: 'axis',
    axisPointer: {
      type: 'shadow'
    }
  },
  grid: {
    left: '3%',
    right: '4%',
    top: '15%',
    bottom:'5%',
    containLabel: true
  },
  xAxis: {
    name:'月',
    type: 'category',
    data: barOneData.xData,
    axisTick: {
      alignWithLabel: true
    }
  },
  yAxis: {
    name:'单位:立方米',
    type: 'value',
    min: 0,
    max: 200
  },
  series: [
    {
      data: barOneData.sData,
      type: 'bar'
    }
  ]
};
function initChart(canvas, width, height, dpr) {
  chart = echarts.init(canvas, null, {
    width: width,
    height: height,
    devicePixelRatio: dpr // new
  });
  canvas.setChart(chart);
  chart.setOption(barOneOption);
  return chart;
}
Page({
  data: {
    bar:{
      onInit: initChart
    }
  },
  ...
})

这样,一个简单的柱状图就渲染好了。

image.png

所有种类的echart图,如饼图、折线图、柱状图等都适用以上逻辑,对于不同种类的echart图只需要改变option的内容即可。

动态echarts图

大多数情况,echart图表的数据会根据服务的数据动态变化,这个时候该如何动态改变数据呢?

如果我们直接改变数据源会不会得到想要的结果? 比如:我们增加一个按钮,点击按钮的时候更改一下数据源

<!--pages/bar/bar.wxml-->
<view>
  <button  bindtap="changeData" type="primary"> 更换数据源 </button>
  <view class="echartBox">
    <ec-canvas id="mychart-dom-bar" canvas-id="mychart-bar" ec="{{ bar }}"></ec-canvas>
  </view>
</view>

changeData函数中更改上诉例子的barOneData, 另外再重新赋值给barOneOption

// pages/bar/bar.js
Page({
  data: {
    bar:{
      onInit: initChart
    }
  },
  changeData: function(){
    barOneData = {
      xData: [1,2, 3, 4, 5, 6, 7,8,9,10,11,12],
      sData: [105, 111, 115, 126, 143, 201, 165,167,152,102,,]
    }
    barOneOption.series[0].data = barOneData.sData;
    barOneOption.xAxis.data = barOneData.xData;
    console.log(barOneData,barOneOption);
  }, 
  ...
})

点击柱状图上方的按钮,发现柱状图的数据并没有改变,但是控制台中输出的数据已经发生了变化:

image.png

why?

一开始,我以为是因为逻辑层改变数据之后,没有将变化后的数据发送到视图层。但是要将数据发送到视图层需要使用setData, 而setData是将页面data中的数据发送到视图层的。根据这个逻辑,我改造了一下代码

将echart图表样式配置单独封装

为了代码整洁,单独把echart的option独立出来, 根据具体的需求,可以接收相应的数据作为参数:

// oneSeriesOption.js
// 一个系列的柱图、折线图
function getOption(data){
  // data示例
  // data:{
  //   sType: 'bar',
  //   xData: [1,2, 3, 4, 5, 6, 7,8,9,10,11,12],
  //   xName: '月',
  //   yData: [100, 110, 113, 126, 143, 158, 165,167,152,102,,],
  //   yName: '单位:立方米',
  // }
  var option = {
    tooltip: {
      trigger: 'axis',
      axisPointer: {
        type: 'shadow'
      }
    },
    grid: {
      left: '3%',
      right: '8%',
      top: '15%',
      bottom:'5%',
      containLabel: true
    },
    xAxis: {
      name:data.xName,
      type: 'category',
      data: data.xData,
      axisTick: {
        alignWithLabel: true
      }
    },
    yAxis: {
      name:data.yName,
      type: 'value'
    },
    series: [
      {
        data: data.yData,
        type: data.sType
      }
    ],
    color:['#83bff6']
  }
  return option
}
module.exports = { //必须在这里暴露接口,以便被外界访问,不然就不能访问
  getOption: getOption,
}

使用封装好的echart图(使用懒加载初始化echart图表)

  • 首先在搭建页面模板
<!--barChange.wxml-->
<view>
  <view class="echartBox">
    <ec-canvas id="mychart-dom-bar" canvas-id="mychart-bar" ec="{{ bar }}"></ec-canvas>
  </view>
</view>
  • 然后在逻辑页面引入
  1. 引入echart、以及封装好的option 文件
// barChange.js
import * as echarts from '../../conn/ec-canvas/echarts';
var getOneSeriesOption= require("../../conn/pageEchart/oneSeriesOption.js");
  1. 初始化数据,这里需要注意,这里动态更新echart,使用了懒加载。也就是在 ec属性中定义的对象是{lazyLoad: true}:
// barChange.js
...
Page({
  data: {
    bar: {
      lazyLoad: true // 延迟加载
    }
  },
  ...
})
  1. 在页面加载的时候,初始化数据,这里主要分为两部分,一部分是拿到数据,另一部分是初始化echart视图。

a. 先封装初始化echart视图函数init_bar,这里需要先获取到视图层的echart元素:this.barComponent = this.selectComponent("#mychart-dom-bar");, 然后使用this.barComponent.init函数对echarts初始化,再使用setOption函数设置option。这样整个echart渲染的函数就写好了:

// barChange.js
...
Page({
  ...
  //初始化柱状图
  init_bar: function (initData) {
    this.barComponent.init((canvas, width, height) => {
      // 初始化图表
      const barChart = echarts.init(canvas, null, {
        width: width,
        height: height
      });
      barChart.setOption(getOneSeriesOption.getOption(initData));
      // 注意这里一定要返回 chart 实例,否则会影响事件处理等
      return barChart;
    });
  },
})

b. 另外,为了方便后面切换数据也将数据变化单独写到一个方法selData里,在数据都准备好之后,传给init_bar即可:

// barChange.js
...
Page({
  data: {
    showIdx: 0,
    bar: {
      lazyLoad: true // 延迟加载
    },
    initData:{}
  },
  selData:function(){
    let data = {
      sType: 'bar',
      xData: [1,2, 3, 4, 5, 6, 7,8,9,10,11,12],
      xName: '月',
      yData: [88,152,163,168,176,133,110,105,88,89,102,115],
      yName:  "单位:立方米"
    }
    this.setData({
      initData:data
    })
    this.barComponent = this.selectComponent("#mychart-dom-bar");
    this.init_bar(this.data.initData);
  },
})

c. 最后在页面加载的时候,直接调用selData就行了:

// barChange.js
Page({
  ...
  onLoad: function (options) {
    this.selData()
  },
})

这样,柱状图就在页面渲染完成了

image.png

到这里,就只是对静态echart做了懒加载,还是不能动态改变数据。

切换按钮实现动态改变echart

  • 在页面上方添加两个按钮,点击按钮的时候传入index参数用来区分点击的是哪个按钮,然后切换数据:
<!--barChange.wxml-->
...
  <view class="box">
    <button type="primary" plain="true" class="minBtn" bindtap="changeChart" data-index="0">柱状图</button>
    <button type="primary" plain="true" class="minBtn"  bindtap="changeChart" data-index="1">曲线图</button>
  </view>
...
  • 根据点击不同的按钮,将点击时的参数index赋值给事先定义好的变量showIdx,改写一下之前获取数据的函数,在点击事件中调用该函数就实现了echart的动态变化:
// barChange.js
Page({
  ...
  // 点击按钮切换echart
  changeChart:function(e){
    this.data.showIdx = e.target.dataset.index;
    // this.data.showIdx = e.detail.index;
    this.setData({
      showIdx:this.data.showIdx 
    })
    this.selData();
  },
  // 根据不同的按钮展示不同的echart图
  selData:function(){    
    if(this.data.showIdx == 0){
      data = {
        sType: 'bar',
        xData: [1,2, 3, 4, 5, 6, 7,8,9,10,11,12],
        xName: '月',
        yData: [88,152,163,168,176,133,110,105,88,89,102,115],
        yName:  "单位:立方米"
      }
    }else{
      data = {
        sType:'line',
        xData: ['1/9','2/9','3/9','4/9','5/9','6/9','7/9'],
        xName: '日',
        yData: [3.7,3.5,2.9,3.2,3.3,2.8,3.5],
        yName: "单位:立方米"
      }
    }
    this.setData({
      initData:data
    })
    this.barComponent = this.selectComponent("#mychart-dom-bar");
    this.init_bar(this.data.initData);
  }    
  ...
})

点击曲线图按钮:

image.png

点击柱状图按钮:

image.png

这样就实现了echart动态改变功能。

思考

在上述实现echart动态变化过程中,主要使用了懒加载。 其实可以看到在根据点击不同的按钮展示不同的echart图的时候,最后还是使用了init_bar函数,这个函数的重点在于对echart视图层元素的初始化函数也就是this.barComponent.init,这是不是类似vue框架中使用echart更新完数据之后需要使用refreshOption更新一下echart图层呢?

image.png

根据这个猜测,我对之前未能成功切换数据源的页面进行了改造,在数据改变之后再次调用echart的init函数, d当然这里不能直接调用一开始写好的initChart, 因为initChart是在页面初始化数据的时候直接挂载到ec对象上的,能够直接挂在到echart对应的实例上进行渲染。而这里,我们需要通过小程序的this.selectComponent先获取到echart组件的实例对象,再对该实例渲染echart图:

// pages/bar/bar.js
Page({
  data: {
    bar:{
      onInit: initChart
    }
  },
  changeData: function(){
    barOneData = {
      xData: [1,2, 3, 4, 5, 6, 7,8,9,10,11,12],
      sData: [105, 111, 115, 126, 143, 201, 165,167,152,102,,]
    }
    barOneOption.series[0].data = barOneData.sData;
    barOneOption.xAxis.data = barOneData.xData;
    console.log(barOneData,barOneOption);
    this.barComponent = this.selectComponent("#mychart-dom-bar");
    this.barComponent.init((canvas, width, height) => {
      const barChart = echarts.init(canvas, null, {
        width: width,
        height: height
      });
      barChart.setOption(barOneOption);
      return barChart;
    });
  }, 
  ...
})

这样,点击切换数据按钮,惊奇的发现echart图的数据发生了改变

image.png

总结: echart图动态改变数据的关键是再改变数据之后,使用echart的init方法重新渲染echart视图。对于以上两种方法我感觉都是可行的,需要使用懒加载的时候使用懒加载的例子,对于不需要懒加载的时候直接之后后者会方便很多。

结束语

这篇文章主要是在做公司业务中时需要使用微信小程序图表的简要记录,由于公司刚开始开发小程序项目,刚开始接触,在开发过程中走了不少弯路,于是做了整理。对于理解得不对的地方,希望各位大佬能多多指教!

参考链接:

微信开放文档

echarts-for-weixin