微信小程序二维码生成器:从生成到识别跳转的完整指南 简介面向微信小程序开发者的二维码生成器源码包基于原生小程序框架实现适用于需要将网址或页面路径快速转为二维码、便于推广与分享的轻量场景。资源完整包含前端页面与核心逻辑页面结构、工具封装、二维码生成模块与全局配置一应俱全导入微信开发者工具即可预览运行。压缩包共15个文件整体仅15KB其中JavaScript负责业务逻辑与二维码生成JSON用于页面及项目配置WXSS定义界面样式WXML搭建页面骨架结构清晰且依赖极少便于初学者按模块拆解也适合开发者快速改造或二次开发。在价值层面读者可以从中掌握小程序基础目录组织、二维码生成与调用的完整思路并可直接将界面样式、配色或Logo等自定义能力移植到自身项目中。对于企业或运营人员也适合在小程序内集成扫码跳转、活动推广等场景。目前已有1275人学习下载是快速上手小程序二维码功能的实用参考。1. 微信小程序二维码生成器生成不是重点识别才是很多人拿到“微信小程序二维码生成器”这个需求第一反应是找个库把字符串画成二维码图片画完之后才发现问题一个接一个用户长按图片没有识别按钮、不同机型上二维码发糊、扫码进不来小程序、带了参数的链接被截断。二维码生成器在小程序里的真正难点不是“生成”这个动作而是“生成之后这张码能在微信的生态里被正确消费”。下面先把三条主流实现路径的选型摆出来再在 canvas 2d 上跑通一个最小可用的完整例子最后把从生成到触发跳转的链路按顺序排查一遍。适合正在做分享海报、扫码引流、渠道追踪或者在 iOS 上遇到二维码存不下来、参数对不上的开发者。2. 二维码生成器三种路径服务端出图、页面画布与官方小程序码动手前先回答一个问题这张二维码的“消费端”是谁。如果用户拿手机相册扫普通 QR 码里放链接就够了如果用户用微信“扫一扫”并且要求直接落到小程序内部页面就需要官方小程序码或者 URL Link 做二次包装。基于这个前提一个微信小程序项目实例里二维码生成器通常落在三条路径上。2.1 服务端生成图片适合批量内容与既有后端内容在服务端已经完整、且可能要批量落地的场景优先让后端直接出图。以 Node 的 qrcode 库为例最精简的接口长这样const QRCode require(qrcode); router.get(/qr, async (req, res) { const url decodeURIComponent(req.query.url || ); res.type(image/png); await QRCode.toFileStream(res, url, { errorCorrectionLevel: M, width: 400, margin: 2 }); });这个接口返回一张 PNG 图片小程序端直接用image srchttps://your-domain.com/qr?url...显示。两个参数值得解释errorCorrectionLevel是容错等级分 L、M、Q、H 四档之后要在二维码中间贴 logo 或者价格标签至少开到 M遮挡面积大就上 Qmargin是白边宽度单位是码的模块个数不要设成 0否则很多扫码应用会提示无法识别。这条路适合会议签到、桌贴、物料打印这类“内容固定、批量产出”的需求。注意两点image的src走网络地址时需要在小程序后台配置 downloadFile 合法域名如果不想配域名可以让后端返回 base64把data:image/png;base64,xxx直接赋给src这样能绕过域名校验但 base64 会撑大 page data只适合小尺寸图。2.2 前端 canvas 绘制适合用户现场产生的动态内容当二维码内容不是后端预先知道的而是用户当场输入的邀请码、文本或临时参数时前端生成是成本最低的选型。社区里流传较广的做法是拿 weapp.qrcode 这类自包含 JS 库把文件放进 utils 目录在页面里 require 后直接在 canvas 上画。const QRCode require(../../utils/weapp.qrcode.js); // 旧版 canvas 的调用方式5 行就能出图 new QRCode(qr-canvas, { text: https://example.com/path?codeAB12, width: 180, height: 180, padding: 12, colorDark: #000000, colorLight: #ffffff, correctLevel: QRCode.CorrectLevel.M });text是二维码承载的原始内容什么字符串都可以塞但只有能被正确扫描才有意义纯中文文本扫出来就是文字以 http/https 开头的链接扫出来会先打开网页带参数的链接建议整体做一次encodeURIComponent否则问号和等号会被部分扫码应用提前截断。correctLevel与后端参数是同一套容错体系前端默认给 M准备在中央贴 logo 时才提级到 H。这条路径不依赖网络也不依赖服务端渲染适合“用户输入一段内容立即生成”的工具型页面。它生成的始终是普通 QR 码微信扫一扫不能直接拉起小程序内部页面要把用户带进小程序还得配 URL Link 或 URL Scheme 包装。2.3 官方接口生成小程序码扫码直达小程序内部页如果产品需求是“扫码打开小程序里的某张页面并且带着来源标识”那就该换用官方小程序码而不是硬把链接塞进普通 QR。最常用的接口是getwxacodeunlimit// 服务端用小程序 access_token 换取小程序码图片 // 以下用 fetch 演示Node 端按你自己的请求库调整即可 const res await fetch( https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token token, { method: POST, body: JSON.stringify({ scene: u_1001, page: pages/detail/index, check_path: false, env_version: release }) } ); const buffer await res.arrayBuffer(); // 二进制图片这里scene是扫码后带进小程序的参数限制为 32 个可见字符page必须是小程序里真实存在且已发布的页面路径。官方接口和普通二维码生成器的本质区别在于扫码后微信直接拉起小程序对应页面而不是先开一个网页。涉及渠道统计、邀请人关系、批次溯源时优先走这条路不要用普通 QR 绕一圈。三条路径的差异整理成一张选型表路径生成位置码类型扫码直达小程序典型场景后端生成图片服务端普通 QR需要 URL Link 包装物料、桌贴、批量打印前端 canvas 绘制用户设备普通 QR需要 URL Link 包装动态文本、本地工具官方小程序码微信服务端小程序码原生支持渠道统计、活动落地选型可以精简成一句话能被服务端预生成的走 2.1用户当场输入的走 2.2要统计来源并跳回小程序页面的走 2.3。实际项目里最常见的是 2.2 与 2.3 混用页面上用临时 canvas 生成海报海报里的小程序码来自官方接口。3. 在微信小程序页面里用 canvas 2d 生成二维码的正确姿势3.1 为什么从 canvas 2d 而不是旧版 canvas 开始微信基础库 2.9.0 之前canvas 是原生组件层级最高页面有弹窗或吸底按钮时二维码会被盖在上面体验很差。2.9.0 起新增 canvas 2d走同层渲染样式、事件和普通 view 一致二维码不再有层级穿透问题。新项目直接写type2d别再使用wx.createCanvasContext那套老写法除非是在维护老项目、老页面本来就能跑。canvas 2d 的第一个差异是获取方式画布节点必须在onReady之后通过createSelectorQuery().fields({ node: true, size: true })取得不能像旧版那样直接传一个 canvasId 字符串给库。3.2 可运行的最小实现WXML 里放一个画布样式尺寸决定二维码在页面中的视觉大小view classqr-wrap canvas type2d idqr-canvas stylewidth: 200px; height: 200px;/canvas /view页面 JS// pages/qr/index.js const QRCode require(../../utils/weapp.qrcode.js); // 支持 canvas 2d 的版本 Page({ data: { qrText: https://example.com/activity?fromqr }, onReady() { this.drawQRCode(); }, drawQRCode() { this.createSelectorQuery() .select(#qr-canvas) .fields({ node: true, size: true }) .exec((res) { if (!res || !res[0]) { console.error(canvas 节点未找到); return; } const { node: canvas, width, height } res[0]; const dpr wx.getWindowInfo ? wx.getWindowInfo().pixelRatio : 2; canvas.width width * dpr; canvas.height height * dpr; const ctx canvas.getContext(2d); ctx.scale(dpr, dpr); // 把实例挂到 this 上后续 canvasToTempFilePath 导出要用 this.canvas canvas; this.drawWidth width; this.drawHeight height; // 注意不同 fork 的第二个参数可能有差异有的直接传 { ...config } new QRCode(canvas, { text: this.data.qrText, width: width, height: height, padding: 10, correctLevel: QRCode.CorrectLevel.M, colorDark: #000000, colorLight: #ffffff }); }); } });逻辑上分四步fields({ node: true, size: true })同时拿到 canvas 实例与 CSS 像素尺寸把画布真实宽高设为CSS 宽度 × dpr这是 canvas 2d 适配高清屏的标准做法漏掉这一步导出图在手机上会发糊ctx.scale(dpr, dpr)让后续绘制仍按 CSS 像素计算否则内容会缩到左上角最后把编码好的模块点交给库画上去。padding是二维码四周白边建议 8 到 12colorDark是深色模块颜色可以改成品牌深色但别用 #f0f0f0 这类浅灰对比度不够会扫不出来correctLevel纯文本内容用 M要贴 logo 用 H。参数建议值说明width / height200~400显示尺寸导出图再乘 2 保证清晰padding8~12白边至少留一个模块宽度correctLevelM / HM 够用中央贴图时上 HcolorDark#000000深色模块色保持深色系colorLight#ffffff背景色深色海报需先铺底色提示不同分支的 weapp.qrcode 在构造函数参数上存在差异拿到库文件后先翻一眼说明确认传的是 canvasId 字符串还是 canvas 实例。3.3 两个常见坑节点拿不到与绘制时机错位坑一在onLoad里就去查节点此时画布还没完成布局fields 回调拿不到 node。把绘制动作放到onReady或者包一层wx.nextTick。坑二二维码画完马上调用canvasToTempFilePath导出结果是空白的。这类库大多是同步绘制保险做法是把导出动作放在绘制函数的后续逻辑里而不是在onReady里靠 setTimeout 猜时间。遇到“生成的二维码扫不出来”按顺序自查四个原因内容开头是否被截断、容错率是不是 L 档、图片实际尺寸是否被压缩到一百像素以内、白色边距是否被后端裁掉了。这四个原因覆盖九成以上的扫不出场景。4. 微信小程序二维码的保存、长按识别与授权引导4.1 长按识别只认 image不认 canvas很多人在 canvas 画完二维码后发现长按没有识别按钮于是怀疑是库的问题。真实原因是微信的长按识别能力只作用于image组件canvas 里的像素不参与图片识别。所以无论如何最终给用户看的二维码都应该是一张图片而不是画布本身。常见项目结构是这样用一个放在页面可视区域外的 canvas 专门负责生成和导出完成后把临时图片路径 setData 到 data 里页面上用image展示这张临时图。这样用户长按、保存都发生在同一张图上canvas 只承担一次性绘制工作。4.2 导出并保存到相册的完整写法导出和保存分成两步代码里也建议拆成两个方法handleSave() { // 第一步canvas 导出为临时图片文件 wx.canvasToTempFilePath({ canvas: this.canvas, // canvas 2d 传实例旧版传 canvasId x: 0, y: 0, width: this.drawWidth, height: this.drawHeight, destWidth: this.drawWidth * 2, // 两倍导出避免保存后发虚 destHeight: this.drawHeight * 2, fileType: png, success: (res) { this.tempFilePath res.tempFilePath; this.saveToAlbum(); }, fail: (err) { console.error(导出失败, err.errMsg); } }); }, saveToAlbum() { wx.saveImageToPhotosAlbum({ filePath: this.tempFilePath, success: () wx.showToast({ title: 已保存, icon: success }), fail: (err) { // 常见错误用户之前拒绝过相册权限 if (err.errMsg.includes(auth denied) || err.errMsg.includes(auth deny)) { wx.showModal({ title: 需要相册权限, content: 请在设置页面里把“相册”权限打开才能保存二维码, confirmText: 去设置, success: (r) { if (r.confirm) wx.openSetting(); } }); } } }); }destWidth和destHeight决定导出文件清晰度线上分享场景建议至少是画布尺寸的两倍fileType用 png 还是 jpg 取决于图片里有没有 logo 和渐变底jpg 体积小但会压掉透明背景png 更通用。保存相册前通常还会先走一遍wx.getSetting检查scope.writePhotosAlbum更省事的做法是把授权判断写进 fail 分支第一次点击系统会弹授权窗拒绝后第二次再点就直接进 fail在这里引导wx.openSetting是最稳的兜底路径。注意saveImageToPhotosAlbum在 iOS 和安卓上的errMsg文案略有差异用includes做关键字匹配兼容性最好。导出格式的选择也能从一张小表里快速确认导出格式优点注意点png保留透明背景、无损文件体积偏大jpg体积小、加载快透明区域变黑需先铺白底4.3 导出图片发虚或透明的处理导出后发现二维码四周发灰、贴在深色海报上粘成一片原因是 png 背景默认透明白色区域没有真正画上去。解决办法是在绘制二维码之前先用ctx.fillStyle #ffffff和ctx.fillRect(0, 0, width, height)铺一遍背景或者保持colorLight为白色并在生成时主动填充。跨端项目里还要注意一点用 uniapp 等框架开发微信小程序时canvas 2d 的节点查询必须带.in(this)否则拿到的是组件外部节点。写法差异不大遇到查不到节点时先检查这里。导出的 API 名是uni.canvasToTempFilePath参数与 wx 版本基本一致canvas同样传 2d 实例。5. 微信小程序二维码从生成到触发跳转的链路排查5.1 先确认你生成的是哪一“类”码普通 QR 码扫出来是字符串或网页地址小程序码扫出来直接拉起小程序页面。这是最容易忽略的第一步需求是“扫码后看到小程序页面”内容里放裸 URL 不够要么生成官方小程序码要么用 URL Link 把链接包装成可拉起小程序的短链。页面内长按识别时两者的规则也有差异普通二维码识别后会经过一次确认弹窗小程序码更顺滑。还有一种情况是产品直接甩来一条weixin://dl/business之类的协议链接要求做到二维码里。这类协议只有在微信内置环境中被点击才会处理扫一扫拿到的是个无法识别的协议串正确做法是先转成 URL Link 再生成码。5.2 从生成到触发的自检顺序按下面的表逐项检查能覆盖绝大多数“扫不出来”和“跳不对”的场景检查项判断标准内容是否被截断长 URL 是否整体 encodeURIComponent容错率与尺寸M 起步导出图不低于 400px白边与裁剪二维码四边保留至少一个模块空白跳转链接合法性落地页使用 https且已配置业务域名小程序码 scene 长度可见字符不超过 32 个page 已发布基础库版本canvas 2d 需 2.9.0getWindowInfo 需 2.20.1实际项目里最常见的一幕是小程序码生成成功但扫码后参数丢失。自查方法是在目标页面的onLoad里把 options 完整渲染出来用另一台手机扫码后对比参数是否原样到达// pages/detail/index.js Page({ onLoad(options) { this.setData({ code: options.code || , scene: (options.scene decodeURIComponent(options.scene)) || }); } });普通链接二维码的参数会落在options.q里小程序码的参数会落在options.scene里。页面能从scene还原出业务数据链路就通了。需要登录时再在这个页面上用wx.login拿临时 code 换 token与scene一起发给业务接口。排查时用微信开发者工具的 Network 面板观察页面请求比肉眼猜参数靠谱得多。5.3 把 scene 当“菜单编号”用不硬塞长参数最后是一个复用很久的技巧不让二维码直接背着完整业务数据。scene上限 32 个可见字符适合放短 ID 或映射键真实数据留在服务端。生成端只写scene: c_1001扫码后在onLoad里取到c_1001再用这个值请求一次业务接口拿到活动信息。这样码内容永远是 8 到 12 个字符体积小、识别率高参数变化也不需要重新发码。对跳转链接场景也是一样的思路链接只保留一个短 Location 参数其余内容走服务端映射。从生成到触发跳转的全流程验证本质就是反复比对“生成端写进去的内容”和“扫描端还原出来的内容”是否一致真正要维护的只是服务端里那一条scene - 业务参数的映射记录。本文还有配套的精品资源点击获取