在 taro3 中使用 ec-canvas(echarts-for-weixin)

5,610 阅读2分钟

老项目使用的是 taro-1.3,最近把taro升级到 taro-3.0,在此记录一下遇到的问题

ec-canvas 不能正常运行使用

错误一

TypeError: this.Chart.init is not a function
    at LineChart.refresh (._src_pages_user_assets_components_chart_LineChart2.js:62)
    at UserTest.componentDidMount (._src_pages_user_user-test_user-test.jsx:45)
    at Lf (._node_modules_react-reconciler_cjs_react-reconciler.production.min.js:133)
    at hh (._node_modules_react-reconciler_cjs_react-reconciler.production.min.js:172)
    at define.push../node_modules/scheduler/cjs/scheduler.production.min.js.exports.unstable_runWithPriority (._node_modules_scheduler_cjs_scheduler.production.min.js:18)
    at Pc (._node_modules_react-reconciler_cjs_react-reconciler.production.min.js:36)
    at Zg (._node_modules_react-reconciler_cjs_react-reconciler.production.min.js:169)
    at Og (._node_modules_react-reconciler_cjs_react-reconciler.production.min.js:160)
    at ._node_modules_react-reconciler_cjs_react-reconciler.production.min.js:37
    at define.push../node_modules/scheduler/cjs/scheduler.production.min.js.exports.unstable_runWithPriority (._node_modules_scheduler_cjs_scheduler.production.min.js:18)(env: Windows,mp,1.05.2109101; lib: 2.19.5)

报错原因: 升级后 taro3 不能通过ref直接获取原生微信小程序组件,实际获取的是 TaroElement, 我们可以通过 getCurrentInstance().page.selectComponent('#mychart-area') 方式获取微信原生小程序Node:

import Taro, { getCurrentInstance } from "@tarojs/taro"
getCurrentInstance().page.selectComponent('#mychart-area').init((canvas, width, height) => {
  console.log('canvas', canvas)
  const chart = echarts.init(canvas, null, {
    width: width,
    height: height
  });
  setChartData(chart, data);
  return chart;
});

TaroElement image.png

原生小程序Node image.png

修复以上问题后,又报新的错误:

错误二

TypeError: t.addEventListener is not a function
    at te (._src_pages_user_assets_components_ec-canvas_echarts.js:37)
    at Oi (._src_pages_user_assets_components_ec-canvas_echarts.js:37)
    at ._src_pages_user_assets_components_ec-canvas_echarts.js:37
    at Array.forEach (<anonymous>)
    at P (._src_pages_user_assets_components_ec-canvas_echarts.js:37)
    at ki (._src_pages_user_assets_components_ec-canvas_echarts.js:37)
    at new e (._src_pages_user_assets_components_ec-canvas_echarts.js:37)
    at new t (._src_pages_user_assets_components_ec-canvas_echarts.js:44)
    at Hi (._src_pages_user_assets_components_ec-canvas_echarts.js:44)
    at new e (._src_pages_user_assets_components_ec-canvas_echarts.js:44)(env: Windows,mp,1.05.2109101; lib: 2.19.6)

经过一番研究之后发现,t.addEventListener中的t就是我们的echarts.init方法中的canvas参数,而canvasec-canvas/wx-canvas 中类 WxCanvas 的实例,尝试在该类中添加 addEventListener 方法,错误成功修复😅。

image.png

const chart = echarts.init(canvas, null, {
  width: width,
  height: height
});
// wx-canvas.js
export default class WxCanvas {
  constructor(ctx, canvasId, isNew, canvasNode) {
    this.ctx = ctx;
    this.canvasId = canvasId;
    this.chart = null;
    this.isNew = isNew
    if (isNew) {
      this.canvasNode = canvasNode;
    }
    else {
      this._initStyle(ctx);
    }

    // this._initCanvas(zrender, ctx);

    this._initEvent();
  }
  
  // 新增空函数,修复调用 echarts.init 时报错
  addEventListener () {}

  getContext(contextType) {
    if (contextType === '2d') {
      return this.ctx;
    }
  }
}

完整代码

// pages/index/index.js
import _ from 'lodash'
import React, { Component } from 'react'
import { View } from '@tarojs/components'
import './user-test.less'
import LineChart from '../assets/components/chart/LineChart'

function createChartData () {
  let seriesDataLine = []
  let progressLine = [1,3,2,6,8,2]
  if (progressLine && progressLine.length) {
    seriesDataLine = _.map(progressLine, item => {
      return {
        value: item,
        label: {
          position: item >= 0 ? 'top' : 'bottom'
        }
      }
    })
  } else {
    seriesDataLine = [0, 0, 0, 0, 0, 0]
  }
  const chartData = {
    dimensions: {
      // data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
    },
    measures: [{
      data: seriesDataLine
    }]
  }

  return chartData
}

export default class UserTest extends Component {
  constructor (props) {
    super(props)
    this.lineChart = React.createRef()
    this.state = {
    }
  }

  componentWillMount () {}

  componentDidMount () {
    // 延迟调用,确保 ec-canvas 节点已存在
    setTimeout(() => {
      this.lineChart.current.refresh(createChartData())
    }, 100)
  }

  componentWillUnmount () { }

  componentDidShow () { }

  componentDidHide () { }

  render () {
    return (
      <View className='page-user-test'>
        <View className='line-chart'>
          <LineChart ref={this.lineChart} />
        </View>
      </View>
    )
  }
}
// LineChart.js
import { Component } from "react"
import { getCurrentInstance } from "@tarojs/taro"
import * as echarts from "../ec-canvas/echarts"

function setChartData(chart, data) {
  let option = {
    color: ['#FF4040'],
    xAxis : [
      {
        type: 'category',
        data: [],
        axisTick: {
          alignWithLabel: true
        }

      }
    ],
    grid: {
      left: '5%',
      right: '5%',
      top: '20',
      bottom: '5',
      containLabel: true
    },
    yAxis : [
      {
        type : 'value'
      }
    ],
    series : []
  };
  if (data && data.dimensions && data.measures) {
    option.xAxis[0].data = data.dimensions.data
    option.series = data.measures.map(item => {
      return {
        ...item,
        type:'line',
        smooth: true
      }
    })
  }
  chart.setOption(option);
}

export default class LineChart extends Component {
  constructor(props) {
    super(props)
    this.state = {
      ec: {
        lazyLoad: true
      }
    }
  }

  componentDidMount () {}

  refresh(data) {
    getCurrentInstance().page.selectComponent('#mychart-area').init((canvas, width, height) => {
      console.log('canvas', canvas)
      const chart = echarts.init(canvas, null, {
        width: width,
        height: height
      });
      setChartData(chart, data);
      return chart;
    });
  }

  render() {
    return (
      <ec-canvas
        id='mychart-area'
        canvasId='mychart-area'
        ec={this.state.ec}
      />
    );
  }
}

相关链接