uniapp小程序使用echarts打包过大的问题

3,559 阅读1分钟

1.uni-app引用echarts uniapp开发引用不同的echarts,首先需要下载插件 <a href="https://ext.dcloud.net.cn/plugin?id=1538" > echarts-for - DCloud插件市场 </a>

a906d1832e719bde3bfa277af9235d2.png 使用HBuilder导入之后,会生成一个js_sdk目录或通过下载zip根据自己需要

0312dd16b16b2d57512239e4723326e.png

uni-ec-canvas文件

<template>
  <canvas type="2d" v-if="isUseNewCanvas" class="ec-canvas" :canvas-id="canvasId" @init="init" @touchstart="touchStart"
    @touchmove="touchMove" @touchend="touchEnd">
  </canvas>
  <canvas v-else class="ec-canvas" :canvas-id="canvasId" @init="init" @touchstart="touchStart" @touchmove="touchMove"
    @touchend="touchEnd">
  </canvas>
</template>

<script>
  import WxCanvas from "./wx-canvas";
  import * as echarts from "./echarts";

  let ctx;

  function 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;
  }

  export default {
    props: {
      canvasId: {
        type: String,
        default: () => {
          return "ec-canvas";
        }
      },
      ec: {
        type: Object
      },
      forceUseOldCanvas: {
        type: Boolean,
        value: false
      }
    },
    data() {
      return {
        $curChart: {},
        toHandleList: [],
        isUseNewCanvas: true
      };
    },
    watch: {
      "ec.option": {
        deep: true,
        handler(val, oldVal) {
          this.setOption(val);
        }
      }
    },
    onReady: function() {
      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: {
      compareVersion(v1, v2) {
        v1 = v1.split(".");
        v2 = v2.split(".");
        const len = Math.max(v1.length, v2.length);

        while (v1.length < len) {
          v1.push("0");
        }
        while (v2.length < len) {
          v2.push("0");
        }

        for (let i = 0; i < len; i++) {
          const num1 = parseInt(v1[i]);
          const num2 = parseInt(v2[i]);

          if (num1 > num2) {
            return 1;
          } else if (num1 < num2) {
            return -1;
          }
        }
        return 0;
      },
      init(callback) {
        const version = wx.getSystemInfoSync().SDKVersion;

        let canUseNewCanvas = this.compareVersion(version, "2.9.0") >= 0;
        if (this.forceUseOldCanvas) {
          if (canUseNewCanvas) console.warn("开发者强制使用旧canvas,建议关闭");
          canUseNewCanvas = false;
        }
        this.isUseNewCanvas = canUseNewCanvas && !this.forceUseOldCanvas;
        if (this.isUseNewCanvas) {
          // console.log('微信基础库版本大于2.9.0,开始使用<canvas type="2d"/>');
          // 2.9.0 可以使用 <canvas type="2d"></canvas>
          this.initByNewWay(callback);
        } else {
          const isValid = this.compareVersion(version, "1.9.91") >= 0;
          if (!isValid) {
            console.error(
              "微信基础库版本过低,需大于等于 1.9.91。" +
              "参见:https://github.com/ecomfe/echarts-for-weixin" +
              "#%E5%BE%AE%E4%BF%A1%E7%89%88%E6%9C%AC%E8%A6%81%E6%B1%82"
            );
            return;
          } else {
            console.warn(
              "建议将微信基础库调整大于等于2.9.0版本。升级后绘图将有更好性能"
            );
            this.initByOldWay(callback);
          }
        }
      },
      initByOldWay(callback) {
        // 1.9.91 <= version < 2.9.0:原来的方式初始化
        ctx = wx.createCanvasContext(this.canvasId, this);
        const canvas = new WxCanvas(ctx, this.canvasId, false);
        const that = this
        echarts.setCanvasCreator(() => {
          return canvas;
        });
        // const canvasDpr = wx.getSystemInfoSync().pixelRatio // 微信旧的canvas不能传入dpr
        const canvasDpr = 1;
        var query = wx.createSelectorQuery().in(this);
        query
          .select(".ec-canvas")
          .boundingClientRect(res => {
            if (typeof callback === "function") {
              that.$curChart = callback(canvas, res.width, res.height, canvasDpr);
            } else if (that.ec) {
              that.initChart(canvas, res.width, res.height, canvasDpr)
            } else {
              that.triggerEvent("init", {
                canvas: canvas,
                width: res.width,
                height: res.height,
                devicePixelRatio: canvasDpr // 增加了dpr,可方便外面echarts.init
              });
            }
          })
          .exec();
      },
      initByNewWay(callback) {
        const that = this
        // version >= 2.9.0:使用新的方式初始化
        const query = wx.createSelectorQuery().in(this);
        query
          .select(".ec-canvas")
          .fields({
            node: true,
            size: true
          })
          .exec(res => {
            const canvasNode = res[0].node;

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

            const ctx = canvasNode.getContext("2d");

            const canvas = new WxCanvas(ctx, that.canvasId, true, canvasNode);
            echarts.setCanvasCreator(() => {
              return canvas;
            });

            if (typeof callback === "function") {
              that.$curChart = callback(
                canvas,
                canvasWidth,
                canvasHeight,
                canvasDpr
              );
            } else if (that.ec) {
              that.initChart(canvas, canvasWidth, canvasHeight, canvasDpr)
            } else {
              that.triggerEvent("init", {
                canvas: canvas,
                width: canvasWidth,
                height: canvasHeight,
                devicePixelRatio: canvasDpr
              });
            }
          });
      },
      setOption(val) {
        if (!this.$curChart || !this.$curChart.setOption) {
          this.toHandleList.push(val);
        } else {
          this.$curChart.setOption(val);
        }
      },
      canvasToTempFilePath(opt) {
        if (this.isUseNewCanvas) {
          // 新版
          const query = wx.createSelectorQuery().in(this);
          query
            .select(".ec-canvas")
            .fields({
              node: true,
              size: true
            })
            .exec(res => {
              const canvasNode = res[0].node;
              opt.canvas = canvasNode;
              wx.canvasToTempFilePath(opt);
            });
        } else {
          // 旧的
          if (!opt.canvasId) {
            opt.canvasId = this.canvasId;
          }
          ctx.draw(true, () => {
            wx.canvasToTempFilePath(opt, this);
          });
        }
      },

      touchStart(e) {
        if (this.ec.stopTouchEvent) {
          e.preventDefault();
          e.stopPropagation();
          return;
        }
        this.$emit("touchstart", e);
        if (this.$curChart && e.touches.length > 0) {
          var touch = e.touches[0];
          var handler = this.$curChart.getZr().handler;
          if (handler) {
            handler.dispatch("mousedown", {
              zrX: touch.x,
              zrY: touch.y
            });
            handler.dispatch("mousemove", {
              zrX: touch.x,
              zrY: touch.y
            });
            handler.processGesture(wrapTouch(e), "start");
          }
        }
      },

      touchMove(e) {
        if (this.ec.stopTouchEvent) {
          e.preventDefault();
          e.stopPropagation();
          return;
        }
        this.$emit("touchmove", e);
        if (this.$curChart && e.touches.length > 0) {
          var touch = e.touches[0];
          var handler = this.$curChart.getZr().handler;
          if (handler) {
            handler.dispatch("mousemove", {
              zrX: touch.x,
              zrY: touch.y
            });
            handler.processGesture(wrapTouch(e), "change");
          }
        }
      },

      touchEnd(e) {
        if (this.ec.stopTouchEvent) {
          e.preventDefault();
          e.stopPropagation();
          return;
        }
        this.$emit("touchend", e);
        if (this.$curChart) {
          const touch = e.changedTouches ? e.changedTouches[0] : {};
          var handler = this.$curChart.getZr().handler;
          if (handler) {
            handler.dispatch("mouseup", {
              zrX: touch.x,
              zrY: touch.y
            });
            handler.dispatch("click", {
              zrX: touch.x,
              zrY: touch.y
            });
            handler.processGesture(wrapTouch(e), "end");
          }
        }
      },

      initChart(canvas, width, height, canvasDpr) {
        this.$curChart = echarts.init(canvas, null, {
          width: width,
          height: height,
          devicePixelRatio: canvasDpr
        });
        canvas.setChart(this.$curChart);
        this.$curChart.setOption(this.ec.option);
      }
    }
  };
</script>

<style lang="scss">
  .ec-canvas {
    width: 100%;
    height: 100%;
    display: block;
  }
</style>

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();
  }

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

  // canvasToTempFilePath(opt) {
  //   if (!opt.canvasId) {
  //     opt.canvasId = this.canvasId;
  //   }
  //   return wx.canvasToTempFilePath(opt, this);
  // }

  setChart(chart) {
    this.chart = chart;
  }

  attachEvent() {
    // noop
  }

  detachEvent() {
    // noop
  }

  _initCanvas(zrender, ctx) {
    zrender.util.getContext = function () {
      return ctx;
    };

    zrender.util.$override('measureText', function (text, font) {
      ctx.font = font || '12px sans-serif';
      return ctx.measureText(text);
    });
  }

  _initStyle(ctx) {
    var styles = ['fillStyle', 'strokeStyle', 'globalAlpha',
      'textAlign', 'textBaseAlign', 'shadow', 'lineWidth',
      'lineCap', 'lineJoin', 'lineDash', 'miterLimit', 'fontSize'
    ];

    styles.forEach(style => {
      Object.defineProperty(ctx, style, {
        set: value => {
          if (style !== 'fillStyle' && style !== 'strokeStyle' ||
            value !== 'none' && value !== null
          ) {
            ctx['set' + style.charAt(0).toUpperCase() + style.slice(1)](value);
          }
        }
      });
    });

    ctx.createRadialGradient = () => {
      return ctx.createCircularGradient(arguments);
    };
  }

  _initEvent() {
    this.event = {};
    const eventNames = [{
      wxName: 'touchStart',
      ecName: 'mousedown'
    }, {
      wxName: 'touchMove',
      ecName: 'mousemove'
    }, {
      wxName: 'touchEnd',
      ecName: 'mouseup'
    }, {
      wxName: 'touchEnd',
      ecName: 'click'
    }];

    eventNames.forEach(name => {
      this.event[name.wxName] = e => {
        const touch = e.touches[0];
        this.chart.getZr().handler.dispatch(name.ecName, {
          zrX: name.wxName === 'tap' ? touch.clientX : touch.x,
          zrY: name.wxName === 'tap' ? touch.clientY : touch.y
        });
      };
    });
  }

  set width(w) {
    if (this.canvasNode) this.canvasNode.width = w
  }
  set height(h) {
    if (this.canvasNode) this.canvasNode.height = h
  }

  get width() {
    if (this.canvasNode)
      return this.canvasNode.width
    return 0
  }
  get height() {
    if (this.canvasNode)
      return this.canvasNode.height
    return 0
  }
}

2.在需要用到的页面引入即可

<template>
    <view>
            <uni-ec-canvas class="uni-ec-canvas" id="uni-ec-canvas" ref="canvas" canvas-id="uni-ec-canvas" :ec="ec">
            </uni-ec-canvas>
    </view>
</template>
 
<script>
import uniEcCanvas from '@/components/uni-ec-canvas/uni-ec-canvas.vue'
let chart = null
export default {
        components: {
                uniEcCanvas
        },
        data() {
                return {
                        ec: {
                                lazyLoad: true
                        },
                        option: {
                                tooltip: {
                                        trigger: 'axis',
                                        axisPointer: { // 坐标轴指示器,坐标轴触发有效
                                                type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
                                        }
                                },
                                grid: {
                                        left: '40',
                                        right: '40',
                                        bottom: '3%',
                                        containLabel: true
                                },
                                xAxis: {
                                        type: 'category',
                                        axisTick: {
                                                show: false,
                                        },
                                        nameTextStyle: {
                                                color: '#666666'
                                        },
                                        axisLabel: {
                                                show: true,
                                                textStyle: {
                                                        color: '#666',
                                                        fontSize: '12',
                                                        fontWeight:'bold'
                                                }
                                        },
                                        axisLine: {
                                                lineStyle: {
                                                        color: '#666',
                                                        width: 1
                                                }
                                        },
                                        data: ["寿险", "重疾", "意外", "医疗", "年金"],
                                },
                                yAxis: {
                                        type: 'value',
                                        axisLine: {
                                                show: false, //y轴线消失

                                        },
                                        axisLabel: {
                                                show: true,
                                                textStyle: {
                                                        color: '#666',
                                                        fontSize: '11'
                                                }
                                        },

                                        axisTick: {
                                                show: false,
                                        },
                                },
                                series: [{
                                        barWidth: 20,
                                        type: 'bar',
                                        data: [20, 50, 40, 10, 20],
                                        itemStyle: {
                                                normal: {
                                                        //每根柱子颜色设置
                                                        color: function(params) {
                                                                const colorList = ["#FFC600", "#21A5FF", "#FF6000", "#00D69C",
                                                                        "#998BFF"
                                                                ];
                                                                return colorList[params.dataIndex];
                                                        }
                                                }
                                        },
                                        label: {
                                                show: true,
                                                position: 'top',
                                                formatter: '{c}万',
                                                color: '#666666',
                                                fontStyle: 'PingFang SC',
                                                fontWeight: 'bold',
                                                fontSize:'8'
                                        }
                                }]
                        },
                }
        },
        methods: {
                initChart(canvas, width, height, canvasDpr) {
                        console.log(canvas, width, height, canvasDpr)
                        chart = echarts.init(canvas, null, {
                                width: width,
                                height: height,
                                devicePixelRatio: canvasDpr
                        })
                        canvas.setChart(chart)
                        chart.setOption(this.option)
                        return chart
                },
        },
        onLoad() {
                setTimeout(() => {
                        console.log(this.$refs)
                }, 2000)
                this.$refs.canvas.init(this.initChart)
        },
}
</script>
 
// 这里一定要注意 设置该组件宽高 以及display:block来确保canvas初始化的时候是有宽高的
<style>
.uni-ec-canvas {
        width: 100%;
        height: 500rpx;
        display: block;
        margin-top: 30rpx;
}
</style>

3.在使用echarts文件打包发布时会说包过大无法打包发布

了解小程序分包将使用到的相关文件分包独立出来

然后将manifest.js内的subPackages设置为true

0ae120112d89fed3ae225376e28a969.png