必须用 uni.createCanvasContext 手动绘制并严格匹配 canvas-id,按 devicePixelRatio 缩放画布尺寸、坐标及图像资源,预加载网络图转本地路径,导出前压缩至 120KB 内。

微信小程序分享图在 uni-app 里用 Canvas 绘制,核心不是“能不能画”,而是“画出来微信认不认、清不清、糊不糊”。直接结论:必须绕开页面截图,全程用 uni.createCanvasContext 手动绘制,且尺寸、压缩、像素比三者不踩准,100% 模糊或被微信二次压缩。
canvas-id 和实际 canvas 元素必须严格匹配
很多报错如 canvas context not found 或绘制空白,根源是 DOM 中的 canvas 元素没被正确识别。uni-app 的 Canvas 渲染机制和原生 Web 不同,不能靠 class 或 ref 查找,只认 canvas-id 字符串匹配。
-
canvas-id必须是纯字符串(如"shareCanvas"),不能带变量插值或空格 - 模板中
要写在当前组件的内,不能放在子组件或条件渲染外层 - 创建上下文时传入的 id 必须完全一致:
uni.createCanvasContext("shareCanvas", this),第二个参数this缺失会导致 H5 正常但 App 端失效 - App 端建议加
style="position: fixed; top: -9999px;"隐藏画布,避免影响布局;小程序端可设opacity: 0,但不能用v-if控制显隐,否则上下文会断连
绘制尺寸必须按设备像素比缩放
写死 width: 750rpx; height: 600rpx; 是模糊第一大因。rpx 是逻辑单位,Canvas 实际像素由 devicePixelRatio 决定。5:4 封面(750×600 rpx)在 iPhone 14 Pro 上实际需要 1500×1200 物理像素才清晰。
- 先获取设备像素比:
const dpr = uni.getSystemInfoSync().pixelRatio - 设置 canvas 样式宽高仍用 rpx(保持布局比例),但通过
canvas.width/canvas.height属性设置真实像素:canvas.width = 750 * dpr; canvas.height = 600 * dpr - 所有
drawImage和文字坐标都要乘以dpr,否则图像会被自动拉伸模糊 - 注意:
uni.canvasToTempFilePath输出的图片尺寸是逻辑像素(即 750×600),但内容是高清绘制的,微信才能原样接收
图片资源必须预加载并转为本地路径
直接传网络地址给 drawImage 在 App 和小程序端大概率失败或显示空白,错误信息常为 invalid image path 或静默忽略。
- 用
uni.getImageInfo({ src: url })获取网络图,成功后拿到path(临时文件路径)再绘制 - 二维码等动态图建议提前生成并缓存到
uni.getFileSystemManager().saveFile,避免每次分享都请求 - 背景图优先用本地静态资源(
static/下),减少异步等待;若必须用网络图,务必加 loading 状态和失败 fallback(比如纯色底) - 不要用 base64 字符串传给
drawImage,iOS App 端不支持
导出前必须压缩到 120KB 以内
微信对小程序分享封面图有硬性体积限制,实测超过 120 * 1024 字节就会触发服务器端高压缩,导致严重模糊。这不是质量参数能解决的,是必须卡死的红线。
- 先调用
uni.canvasToTempFilePath得到临时路径,再用uni.getFileInfo检查 size - 超限时用
uni.compressImage压缩,关键参数:quality: 60(别设太高)、width: '80%'、height: 'auto' - 压缩后再次检查 size,必要时递归压缩(但最多两轮,避免过度失真)
- 文字尽量用系统默认字体(如
font: 'bold 28px sans-serif'),自定义字体文件会显著增大体积
真正难的不是画出来,是让微信“信得过”这张图:它要够小、够真、够准。dpr 缩放漏一步,压缩超 1KB,canvas-id 错一个字符,都会在用户分享那一刻暴露——不是模糊,就是白图,或者干脆调不起分享菜单。











