Taro3+Vue3使用echarts

Picture first, hang without picture

1. Taro supports echarts

Official description: https://taro-docs.jd.com/blog/2018-09-18-taro-1-0-0#Support citing third-party component libraries on the applet side

2. Introduce echarts-for-weixin plug-in

github address: https://github.com/ecomfe/echarts-for-weixin

Only import wx-canvas.js under the ec-canvas folder

3. Customize download echarts

Address: https://echarts.apache.org/zh/builder.html

You can choose the version yourself, the author tested both 5.3.3 and 5.4.1 to support

Get echarts.min.js after downloading

Please choose the chart you need to package and download according to your needs. I only chose the default pie chart, column chart, and line chart;

4. Packaging component ec-canvas.vue

<template>
  <canvas type="2d" class="ec-canvas" :canvas-id="canvasId" @touchStart="touchStart" @touchMove="touchMove"
    @touchEnd="touchEnd"></canvas>
</template>

Introduce the echarts.min.js and wx-canvas just downloaded

import Taro from "@tarojs/taro";
import WxCanvas from "./wx-canvas";
import * as echarts from "./echarts-5.4.1.min";
<script lang="js">
//自定义下载的echarts.min.js 文件  要使用需使用js,ts需要声明文件
import Taro from "@tarojs/taro";
import WxCanvas from "./wx-canvas";
import * as echarts from "./echarts-5.4.1.min";

export default {
  name: "EcCanvas",
  props: {
    canvasId: {
      type: String,
      default: ""
    },
    ec: {
      type: Object,
      default: null
    }
  },
  mounted() {
    echarts.registerPreprocessor(option => {
      if (option && option.series) {
        if (option.series.length > 0) {
          option.series.forEach(series => {
            series.progressive = 0;
          });
        } else if (typeof option.series === "object") {
          option.series.progressive = 0;
        }
      }
    });
    if (!this.ec) {
      console.warn(
        '组件需绑定 ec 变量,例:<ec-canvas id="mychart-dom-bar" ' +
        'canvas-id="mychart-bar" ec="{
    
    { ec }}"></ec-canvas>'
      );
      return;
    }
    if (!this.ec.lazyLoad) {
      this.init();
    }
  },
  methods: {
    init(callback) {
      this.initByNewWay(callback);
    },
    initByNewWay(callback) {
      const query = Taro.createSelectorQuery();
      query
        .select(".ec-canvas")
        .fields({
          node: true,
          size: true
        })
        .exec(res => {
          if (!res || res.length == 0 || res[0] == null || res[0].node == null) {
            console.error('未获取到canvas的dom节点,请确认在页面渲染完成后或节点,taro中页面渲染完成的生命周期是useReady');
            return
          }
          const canvasNode = res[0].node;
          // this.canvasNode = canvasNode;

          const canvasDpr = Taro.getSystemInfoSync().pixelRatio;
          const canvasWidth = res[0].width;
          const canvasHeight = res[0].height;

          const ctx = canvasNode.getContext("2d");
          const canvas = new WxCanvas(ctx, this.canvasId, true, canvasNode);
          echarts.setCanvasCreator(() => {
            return canvas;
          });

          if (typeof callback === "function") {
            this.chart = callback(canvas, canvasWidth, canvasHeight, canvasDpr);
          } else if (typeof this.ec.onInit === "function") {
            this.chart = this.ec.onInit(
              canvas,
              canvasWidth,
              canvasHeight,
              canvasDpr
            );
          } else {
            this.triggerEvent('init', {
              canvas: canvas,
              width: canvasWidth,
              height: canvasHeight,
              dpr: canvasDpr
            })
          }
        });
    },
    canvasToTempFilePath(opt) {
      const query = Taro.createSelectorQuery().in(this);
      query
        .select(".ec-canvas")
        .fields({
          node: true,
          size: true
        })
        .exec(res => {
          const canvasNode = res[0].node;
          opt.canvas = canvasNode;
          Taro.canvasToTempFilePath(opt);
        });
    },
    touchStart(e) {
      if (this.chart && e.touches.length > 0) {
        var touch = e.touches[0];
        var handler = this.chart.getZr().handler;
        handler.dispatch("mousedown", {
          zrX: touch.x,
          zrY: touch.y
        });
        handler.dispatch("mousemove", {
          zrX: touch.x,
          zrY: touch.y
        });
        handler.processGesture(this.wrapTouch(e), "start");
      }
    },
    touchMove(e) {
      if (this.chart && e.touches.length > 0) {
        var touch = e.touches[0];
        var handler = this.chart.getZr().handler;
        handler.dispatch("mousemove", {
          zrX: touch.x,
          zrY: touch.y
        });
        handler.processGesture(this.wrapTouch(e), "change");
      }
    },
    touchEnd(e) {
      if (this.chart) {
        const touch = e.changedTouches ? e.changedTouches[0] : {};
        var handler = this.chart.getZr().handler;
        handler.dispatch("mouseup", {
          zrX: touch.x,
          zrY: touch.y
        });
        handler.dispatch("click", {
          zrX: touch.x,
          zrY: touch.y
        });
        handler.processGesture(this.wrapTouch(e), "end");
      }
    },
    wrapTouch(event) {
      for (let i = 0; i < event.touches.length; ++i) {
        const touch = event.touches[i];
        touch.offsetX = touch.x;
        touch.offsetY = touch.y;
      }
      return event;
    }
  }
};
</script>

<style>
.ec-canvas {
  width: 100%;
  height: 100%;
}
</style>

5. Encapsulate the e-chart.vue component

  1. <script lang=js>

Use js to avoid the introduction of echarts.min.js error reporting, requiring to write the declaration file.d.ts

  1. Do not use setup syntactic sugar <script lang=js setup> will report an error

  1. const ecCanvasRef = ref(null); Use ref in vue3 to get the component instance declaration consistent with the ref variable in the template

  1. Expose vue3 exposes subcomponent methods to the outside world, which is the same as defineExpose in <setup> syntactic sugar

<template>
    <ec-canvas ref="ecCanvasRef" :canvas-id="canvasId" :ec="ec"></ec-canvas>
</template>
  
<script lang="js">
/**
 * 自定义下载的echarts.min.js 文件  要使用需使用js,ts需要声明文件
 * 此组件不能使用setup语法糖,会报错的.
 */
import Taro, { useLoad } from "@tarojs/taro";
import * as echarts from './ec-canvas/echarts-5.4.1.min'
import EcCanvas from './ec-canvas/ec-canvas.vue'
import { ref, reactive } from "vue";
export default {
    components: {
        EcCanvas
    },
    props: {
        canvasId: {
            type: String,
            default: ''
        }
    },
    setup(props, { expose }) {
        const ec = reactive({
            lazyLoad: true
        })
        const ecCanvasRef = ref(null);

        const refresh = (options) => {
            if (!ecCanvasRef.value) {
                console.error('ecCanvas未获取到dom');
                return
            }
            ecCanvasRef.value?.init((canvas, width, height, canvasDpr) => {
                const chart = echarts.init(canvas, null, {
                    width: width,
                    height: height,
                    devicePixelRatio: canvasDpr
                })
                canvas.setChart(chart);
                chart.setOption(options);
                return chart;
            })
        }

        expose({
            refresh,
        })
        return {// 返回值会暴露给模板和其他的选项式 API 钩子
            ec, ecCanvasRef
        }
    },
}
</script>
  

6. Use packaged components

<template>
    <view class="page">
        <view class="bar-chart">
            <EChart ref="barChat" canvas-id="bar-canvas" />
        </view>
        <button type="primary" :plain="true" @tap="onRefreshData">刷新数据</button>
    </view>
</template>
  
<script lang="ts" setup>
import Taro, { useReady } from "@tarojs/taro";
import { ref } from "vue";
import { randomArray } from '@/utils/array-util';
const colors = ref(["#3cb2ef", "#ffed65", "#FD665F", "#59d4d4", "#52d378", "#cc33cc", "#336666"]);
useReady(() => {
    initMultiBarChart();
})
const barChat = ref<any>();
const onRefreshData = () => {
    initMultiBarChart();
}
const initMultiBarChart = () => {
    let yData = [
        {
            Name: "收入",
            Value: randomArray(1000, 12)
        },
        {
            Name: "支出",
            Value: randomArray(992, 12)
        },
    ];
    const options = {
        tooltip: {
            trigger: "axis",
            axisPointer: {
                type: "cross",
                crossStyle: {
                    color: "#999",
                },
            },
        },
        grid: {
            y: 80,
            y2: 20,
            borderWidth: 1,
            // top: '90px',//内边距
            // left: '100px',
            // right: '0px',
            // bottom: '0px'
        },
        color: colors.value,
        legend: {
            data: ["收入", "支出"],
            left: "center",
            top: "1%",
        },
        xAxis: [
            {
                type: "category",
                data: ["1月",
                    "2月",
                    "3月",
                    "4月",
                    "5月",
                    "6月",
                    "7月",
                    "8月",
                    "9月",
                    "10月",
                    "11月",
                    "12月",],
                axisPointer: {
                    type: "shadow",
                },
            },
        ],
        yAxis: [
            {
                type: "value",
                name: "元",
                axisLabel: {
                    formatter: "{value}",
                },
            },
        ],
        series: yData.map((item) => {
            return {
                name: item.Name,
                type: "bar",
                barMaxWidth: 30,
                data: item.Value,
            };
        }),
    };
    Taro.nextTick(() => {
        barChat.value.refresh(options)
    })
}
</script>
  
<style lang="scss">
.bar-chart {
    width: 100%;
    min-height: 500px;
    flex: 1;
}
</style>
  

Seven. Mistakes

  1. ec-canvas中使用Taro.createSelectorQuery()获取不到dom节点

const query = Taro.createSelectorQuery();
      query
        .select(".ec-canvas")
        .fields({
          node: true,
          size: true
        })
        .exec(res=>{
    
})

Taro.createSelectorQuery()获取节点必须在页面渲染完成后,否则获取到的是null;

在组件和页面里获取略有不同,Taro.createSelectorQuery().in(this)在页面里获取

Guess you like

Origin blog.csdn.net/jerry872235631/article/details/129708022