uni-app (Vue3) + ECharts + echarts-for-weixin 集成踩坑记录

前言:
vue3+uniapp+vite+微信小程序真的是buff叠满,尝试各种组件库都存在这样那样的问题,不够丝滑,功能不够丰富,iOS无法兼容,各种改底层失败。ucharts\lime-echarts\echarts+echarts-for-weixin都尝试了个遍,最后发现回退版本到vue2一切就解决了。
不死心的填坑小能手还是控制不住不降版本不改需求的情况下寻求解决方案。
最后,在第二次尝试echarts+echarts-for-weixin终于成功了。
不能开箱即用,也需要改插件底层~
以下描述详情,从报错到改到一切正常的记录
image

uni-app (Vue3) + ECharts + echarts-for-weixin 集成踩坑记录

项目:testvue3withelimeecharts
技术栈:uni-app Vue3 + Vite + 微信小程序
ECharts 版本:5.x(UMD 压缩版 ~1MB)


一、报错明细与解决方案

1. ❌ global is not defined — ECharts 在 Vite 环境找不到 global 对象

报错现象
ECharts 5.x 内部引用了 global 全局变量(用于检测运行环境),但 Vite 是 ESM 环境,默认不存在 global,导致报错 global is not defined

解决方案
vite.config.js 中通过 define 注入 global

// vite.config.js
export default defineConfig({
  plugins: [uni()],
  define: {
    global: 'globalThis'   // ✅ 让 echarts 能找到 global 对象
  }
})

⚠️ 注意define 只对经过 Vite 编译的文件生效。wxcomponents/ 下的原生小程序组件 不经过 Vite 处理,因此 global: 'globalThis' 对 ec-canvas 组件无效——但 ec-canvas 运行在小程序环境,小程序本身有 global 对象,所以不受影响。


2. ❌ 小程序端 import * as echarts from 'echarts' 报错

报错现象
在小程序端使用 ES Module import 引入 echarts 会报错,因为小程序不支持 ESM 模块系统,无法解析 npm 包的 import 语法。

解决方案
使用 uni-app 条件编译,小程序端用 require 引入本地 UMD 文件,其他端用 import

// #ifdef MP-WEIXIN
const echarts = require('../../static/echarts.min.js')   // ✅ 小程序端:require UMD 包
// #endif

// #ifndef MP-WEIXIN
import * as echarts from 'echarts'                        // ✅ 其他端:ESM import
// #endif

关键点

  • 小程序端 不要用 import,必须用 require
  • echarts.min.js 放在 static/ 目录,作为静态资源不参与编译
  • 同样,wxcomponents/ec-canvas/ec-canvas.js 第2行也是用 require('../../static/echarts.min.js') 引入

3. ❌ iOS 白屏 — 未调用 canvas.setChart(chart)

报错现象
图表在 Android 正常显示,但 iOS 设备上白屏,无任何内容渲染。

解决方案
初始化 chart 后,必须将 chart 挂回 canvas 对象:

const chart = echarts.init(canvas, null, {
  width,
  height,
  devicePixelRatio: dpr
})
canvas.setChart(chart)   // ✅ 必须挂回 canvas,否则 iOS 白屏

原因:iOS 的 Canvas 渲染机制要求 chart 实例与 canvas 节点关联,否则 zrender 无法正确绑定绘制上下文。


4. ❌ 原生组件 ec-canvas 在 uni-app 中不显示

报错现象
<ec-canvas> 标签在小程序页面中不渲染或报 "Unknown custom element" 错误。

解决方案
pages.json 中声明 usingComponents

{
  "pages": [
    {
      "path": "pages/index/index",
      "style": {
        "usingComponents": {
          "ec-canvas": "/wxcomponents/ec-canvas/ec-canvas"
        }
      }
    }
  ]
}

关键点

  • 路径必须以 / 开头,表示项目根目录
  • wxcomponents/ 目录下的原生组件 不走 Vite 编译,保持原样复制到构建产物
  • manifest.json 中必须设置 "mp-weixin": { "usingComponents": true }

5. ❌ 旧版 Canvas API 兼容问题 — 基库版本过低

报错现象
微信基础库版本 < 1.9.91 时,canvas 初始化失败,报错 "微信基础库版本过低"。

解决方案
ec-canvas.js 内部已自动处理版本检测:

  • 基库 >= 2.9.0 → 使用新版 <canvas type="2d">(性能更好)
  • 基库 >= 1.9.91 但 < 2.9.0 → 使用旧版 wx.createCanvasContext
  • 基库 < 1.9.91 → 报错,无法使用
// ec-canvas.js 中的版本判断逻辑
const canUseNewCanvas = compareVersion(version, '2.9.0') >= 0
const isUseNewCanvas = canUseNewCanvas && !forceUseOldCanvas

建议:项目 project.config.json 中设置 miniprogram-base-lib 最低版本为 2.9.0+。


6. ❌ echarts progressive 渲染在小程序中不生效

报错现象
开启 progressive 渐进渲染后,图表数据不显示或绘制异常。

解决方案
ec-canvas.jsready 生命周期中注册了 preprocessor,强制关闭 progressive

echarts.registerPreprocessor(option => {
  if (option && option.series) {
    option.series.forEach(series => {
      series.progressive = 0   // ✅ 小程序 canvas 的 drawImage 不支持 DOM 参数
    })
  }
})

原因:小程序 Canvas 的 drawImage API 不支持 DOM 元素作为参数,导致 echarts 的渐进渲染模式失效。


7. ❌ 父容器未设置高度 — 图表区域为 0 不显示

报错现象
ec-canvas 渲染后空白,调试发现 width/height 为 0。

解决方案
父容器必须明确设置高度:

<view style="width: 100%; height: 500rpx;">
  <ec-canvas id="mychart" canvas-id="mychart" :ec="ec" />
</view>
/* 父容器一定要给高度 */
.chart-wrapper {
  width: 100%;
  height: 550rpx;
}

原因:ec-canvas 内部通过 wx.createSelectorQuery().select('.ec-canvas').boundingClientRect() 获取尺寸,如果父容器高度为 0 或 auto,返回的 height 为 0。


8. ❌ DPR(设备像素比)适配问题

报错现象
图表在高 DPI 设备上模糊,或在旧版 Canvas 上缩放异常。

解决方案

  • 新版 Canvas(>= 2.9.0):ec-canvas 自动获取 wx.getSystemInfoSync().pixelRatio,传入 devicePixelRatio: dpr
  • 旧版 Canvas(< 2.9.0):强制 canvasDpr = 1,因为旧版 Canvas 不支持 DPR 适配
// 新版方式
const canvasDpr = wx.getSystemInfoSync().pixelRatio

// 旧版方式
const canvasDpr = 1   // 微信旧的 canvas 不能传入 dpr

初始化时必须传入 dpr

const chart = echarts.init(canvas, null, {
  width,
  height,
  devicePixelRatio: dpr   // ✅ 不能省略
})

9. ❌ WxCanvas 适配层 — echarts 内部 API 调用不兼容

报错现象
echarts 内部调用 canvas.addEventListenercanvas.detachEvent 等浏览器 DOM API,在小程序中不存在。

解决方案
wx-canvas.jsWxCanvas 类作为适配层,补齐了 echarts 需要的所有接口:

class WxCanvas {
  attachEvent() { /* noop */ }
  detachEvent() { /* noop */ }
  addEventListener() { /* noop */ }
  removeEventListener() { /* noop */ }
  setChart(chart) { this.chart = chart }
  getContext(contextType) {
    if (contextType === '2d') return this.ctx
  }
  // ... width/height getter/setter 适配 canvasNode
}

关键点WxCanvas 是 echarts 在小程序上运行的桥梁,必须完整实现 echarts 所依赖的 Canvas 接口。


二、集成架构总结

┌─────────────────────────────────────────────────┐
│  pages/index/index.vue (Vue3 Composition API)   │
│  ┌───────────────────────────────────────────┐  │
│  │ 条件编译引入 echarts:                      │  │
│  │   MP-WEIXIN → require(UMD)                │  │
│  │   其他端   → import(ESM)                  │  │
│  │                                           │  │
│  │ ec = ref({ onInit(canvas, w, h, dpr) })   │  │
│  │   → echarts.init(canvas, null, {...})     │  │
│  │   → canvas.setChart(chart)  // iOS 必须   │  │
│  │   → chart.setOption(option)               │  │
│  │   → return chart                          │  │
│  └───────────────────────────────────────────┘  │
│                     │                            │
│                     ▼                            │
│  <ec-canvas :ec="ec" />                         │
│                     │                            │
└─────────────────────┼────────────────────────────┘
                      ▼
┌─────────────────────────────────────────────────┐
│  wxcomponents/ec-canvas/ (原生小程序组件)        │
│  ┌───────────────────────────────────────────┐  │
│  │ ec-canvas.js                               │  │
│  │   require('../../static/echarts.min.js')   │  │
│  │   require('./wx-canvas.js')                │  │
│  │                                           │  │
│  │   ready → init()                          │  │
│  │     版本检测 → initByNewWay / initByOldWay│  │
│  │     → WxCanvas 适配层                     │  │
│  │     → echarts.setCanvasCreator(() => canvas)│
│  │     → 调用 ec.onInit(canvas, w, h, dpr)   │  │
│  └───────────────────────────────────────────┘  │
│  ┌─────────┐ ┌──────────┐ ┌─────────────────┐ │
│  │ec-canvas│ │ec-canvas │ │wx-canvas.js     │ │
│  │  .wxml  │ │  .wxss   │ │ WxCanvas 适配层 │ │
│  └─────────┘ └──────────┘ └─────────────────┘ │
└─────────────────────────────────────────────────┘
                      │
                      ▼
┌─────────────────────────────────────────────────┐
│  static/echarts.min.js (ECharts 5.x UMD ~1MB)  │
│  → 不参与 Vite 编译,作为静态资源直接复制       │
└─────────────────────────────────────────────────┘

三、最佳实践 Checklist

序号 检查项 配置位置 状态
1 vite.config.js 添加 global: 'globalThis' vite.config.js
2 小程序端用 require 引入 echarts UMD index.vue 条件编译
3 其他端用 import 引入 echarts ESM index.vue 条件编译
4 canvas.setChart(chart) 防止 iOS 白屏 index.vue onInit
5 pages.json 注册 usingComponents pages.json
6 manifest.json 启用 usingComponents: true manifest.json
7 父容器设置明确高度(rpx/px) index.vue style
8 echarts.init 传入 devicePixelRatio index.vue onInit
9 echarts.min.js 放 static/ 目录 static/
10 ec-canvas 组件放 wxcomponents/ 目录 wxcomponents/

四、常见误区提醒

  1. 不要尝试 npm 安装 echarts 再在小程序端使用 — 小程序不支持 npm 包的 ESM 解析,必须用本地 UMD 文件
  2. 不要在 wxcomponents 原生组件中使用 Vue 语法 — ec-canvas 是原生小程序组件,只能用 WXML/WXSS/JS
  3. 不要省略 canvas.setChart(chart) — 即使 Android 正常,iOS 也会白屏
  4. 不要给旧版 Canvas 传入 dpr — 旧版 wx.createCanvasContext 不支持,强制用 1
  5. 不要给 echarts series 开启 progressive — ec-canvas 的 preprocessor 会自动关闭,手动开启会导致绘制异常
  6. ec-canvas 的 idcanvas-id 不能重复 — 多图表场景下每个实例必须用唯一 id
posted @ 2026-06-26 16:36  JocelynFung  阅读(34)  评论(0)    收藏  举报
Live2D 看板娘 / Demo