·更新于 2026年10月25日· 9 次浏览 微信小程序CanvasBUG解决工程实践开发经验

微信小程序分享海报总生成空白:我用离屏 Canvas、图片预下载和字体加载补齐失败链路

小程序海报空白多半不是绘制语法错,而是 Canvas 初始化、图片下载、字体加载和导出时序没对齐。把资源准备前置,并加上重试与降级,流程会稳定很多。

微信小程序分享海报总生成空白:我用离屏 Canvas、图片预下载和字体加载补齐失败链路 封面
ZHOUYI

作者

ZHOUYI

做小程序分享海报时,最怕的不是报错,而是导出图一片空白。后来我发现,多数空白不是绘制代码错了,而是时序没对齐:Canvas 还没初始化完就开始画,图片还在下载,字体没加载完,最后导出了一张没有底图的图。我把链路拆成资源准备、绘制、导出三段,才慢慢稳定下来。

先把失败链路画出来

  • 离屏 Canvas 是否创建成功,宽高是否显式设置,避免尺寸为 0
  • 网络图片是否先 downloadFile 成临时路径,再进入 Image onload
  • 远程字体是否加载完成,失败时是否回退系统字体
  • 导出是否放在下一帧,避免绘制还没完成就生成图片

还有一个容易被忽略的点:下载得到的临时路径并非永久可用。文件被清理、页面重新进入、缓存过期,都可能让上次能用的路径这次画不出来。所以我每次生成海报都会重新走一遍下载和 onload 校验,而不是把旧路径直接塞给 Canvas。

资源准备好再绘制

我现在不会在绘制时直接写网络 URL,而是先用 wx.downloadFile 把背景图、头像、二维码下载到临时路径,再创建 Image。每张图片都包成 Promise,只有全部 onload 后才允许进入绘制。字体也一样:如果业务需要特殊字体,就用 wx.loadFontFace 异步加载,并设置超时;加载失败不阻塞流程,直接回退默认字体。具体能力与参数差异,以官方文档为准。

js
const loadImage = (canvas, src) => new Promise((resolve, reject) => {
  const img = canvas.createImage();
  img.onload = () => resolve(img);
  img.onerror = reject;
  img.src = src;
});
async function prepare(canvas, localPaths) {
  return Promise.all(localPaths.map((p) => loadImage(canvas, p)));
}

导出加重试和降级

绘制完成后,我不再立即导出,而是等下一帧再调用 wx.canvasToTempFilePath。如果失败,会按重下载图片、重绘、降低清晰度导出的顺序重试一次。离屏 Canvas 的好处是不容易被页面显示和滚动影响,但实例、宽高和导出参数都要传对。海报生成这种强依赖外部资源的功能,不能假设网络稳定;把每一步做成可检查、可重试、可降级,空白问题会少很多。

Guestbook

留言

若这篇文章也曾停在你心上,留一行字吧,我会看的。

先确认一下邮箱

多这一步,是为了少些机器骚扰,也让我能更踏实地读每一条真人写下的字。验证码 10 分钟内有效;同一邮箱 60 秒内只能发一封。

本文留言

共 0 条已加载 0 条

这里还静悄悄的——愿意做第一个留下脚印的人吗?