问问今天(AI复盘助手)复盘 — 2026-05-04

本次:分享卡片添加小程序码 + 修复保存权限问题


📋 本次完成

| 事项 | 状态 | 说明 | |------|------|------| | 分享卡片添加小程序码 | ✅ | 白色卡片内右下角,100px | | 保存图片权限修复 | ✅ | app.json + 后台隐私保护指引 | | 小程序码生成 | ✅ | 页面路径 pages/index/index | | 代码提交审核 | ✅ | 待审核通过 |


🔍 深度复盘:分享卡片添加小程序码踩坑记录

坑1:离屏 canvas 加载本地图片失败

场景share-card 组件用 createOffscreenCanvas 画的分享图,canvas.createImage() 加载 /images/qrcode.png 始终不触发 onload

根因:离屏 canvas 不在页面 DOM 中,本地图片路径解析行为与页面 canvas 不同。

教训

  • 离屏 canvas 的图片加载能力有限,本地资源可能加载不到
  • 如果用 createOffscreenCanvas,最好用 toDataURL 直接嵌入 base64 数据
  • 或者改用页面上的 canvas 元素(createSelectorQuery 获取)

坑2:ctx.canvas.createImage 报错 not a function

场景:在 result.js 里用页面 canvas 绘制分享图,调用 ctx.canvas.createImage()TypeError: createImage is not a function

根因createImage 是 canvas 节点的方法,不是 context 的方法。要通过 canvas 对象(res[0].node)调用,不是 ctx.canvas

正确写法

// ❌ ctx.canvas.createImage() — 报错
// ✅ canvas.createImage() — canvas 是 res[0].node
const canvas = res[0].node;
const qrImg = canvas.createImage();

教训:Canvas 2D 的 API 挂在 canvas 节点上,不在 ctx 上。这个很容易搞混。

坑3:异步加载导致导出卡死

场景:小程序码异步加载,canvasToImage 用轮询等待 _qrReady,结果一直卡在 loading。

根因

  1. 如果图片加载失败(路径不对、格式问题等),_qrReady 永远不会被设为 true
  2. toDataURL 在某些情况下也可能卡住
  3. 没有超时机制

教训

  • 异步加载图片必须有超时兜底
  • 不要用轮询等待,用 setTimeout 延迟导出更简单可靠
  • 加载失败不应阻塞整个流程,没码也能出图

坑4:createImage 的 src 赋值时机

场景:先赋值 qrImg.src,再注册 qrImg.onload,导致图片在监听器绑定前就加载完了,onload 不触发。

根因:如果图片已被缓存(之前加载过),src 赋值瞬间就完成加载,此时 onload 还没注册。

正确顺序

const img = canvas.createImage();
img.onload = () => { /* 画图 */ };
img.onerror = () => { /* 处理失败 */ };
img.src = '/images/qrcode.png'; // 最后赋值

坑5:保存图片权限(跟 SBTI 一样的问题)

跟 SBTI 复盘的 errno: 1025 问题完全一致:

  • app.json 需要 permission 声明
  • 微信后台需要配置用户隐私保护指引
  • requiredPrivateInfos 不支持相册权限(只支持地理位置)

💡 最佳实践总结

Canvas 2D 加载图片的标准写法

// 1. 从页面 canvas 节点创建图片
const canvas = res[0].node; // createSelectorQuery 获取
const img = canvas.createImage(); // 不是 ctx.canvas.createImage()

// 2. 先注册回调,再赋值 src
img.onload = () => {
  ctx.drawImage(img, x, y, w, h);
};
img.onerror = () => {
  console.log('图片加载失败');
};
img.src = '/images/xxx.png';

// 3. 导出时给异步操作留缓冲时间
setTimeout(() => {
  wx.canvasToTempFilePath({ canvas, success, fail });
}, 800);

保存图片功能检查清单(与 SBTI 复盘一致)

  • [ ] app.jsonpermission 声明 scope.writePhotosAlbum
  • [ ] 微信后台 → 设置 → 功能设置 → 用户隐私保护指引 → 声明相册(仅写入)
  • [ ] 隐私协议页面包含相册权限说明
  • [ ] 提交审核时勾选「采集用户隐私」
  • [ ] 体验版真机测试保存功能


🔍 深度复盘:2026-05-07 补充踩坑

坑6:页面未实现 onShareAppMessage 导致分享按钮灰色

场景:问问今天上线后,用户反馈右上角菜单的「转发」按钮是灰的,无法点击分享。

根因:页面 JS 中没有定义 onShareAppMessage() 方法。微信的规则是——如果页面没实现这个方法,右上角转发入口会被禁用。

影响:index、history、review、privacy、terms 5个页面全部缺失,严重影响社交传播。SBTI 之前也踩过同样的坑。

修复:给所有页面补上 onShareAppMessage,统一返回分享标题和路径。

教训每个页面都必须实现 onShareAppMessage,开发新小程序时页面模板里就要默认带上。

// 标准写法,每个页面都加
onShareAppMessage() {
  return {
    title: '小程序名称 - 分享标题',
    path: '/pages/index/index',
    imageUrl: '' // 可选
  };
}

坑7:提示文案与实际存储策略不符

场景:历史页面底部显示「数据仅保存在本地,清除缓存会丢失」,但实际数据同时存到了云端。

根因:开发时沿用了纯本地存储的文案模板,没有更新为云开发版本。

修复:直接去掉底部提示文案(用户不想看到涉及云端存储的说明)。

教训:提示文案要跟实际存储策略一致。更好的做法是——不涉及数据存储的说明,避免用户产生隐私顾虑。

坑8:批量修改代码后未验证语法,导致全站白屏

场景:批量给 5 个页面添加 onShareAppMessage 方法时,用 Python 脚本拼接字符串插入代码,但漏了逗号} 后面直接接 onShareAppMessage),导致 5 个页面 JS 语法报错,首页完全无法加载。

根因:脚本拼接时只关注了「代码内容是否正确」,忽略了 JS 对象属性之间必须用逗号分隔的语法规则。

修复:给所有页面的 onShareAppMessage 前面补上逗号。

教训批量修改代码后必须验证语法。至少要做两件事:

  1. node -c file.js 或类似工具检查语法
  2. 在开发者工具里实际编译运行一遍

复盘人:喵喵 | 关键词:onShareAppMessage、分享按钮灰色、提示文案、云存储、语法错误、批量修改、白屏