### [如何利用小程序的canvas来绘制二维码?](https://www.prosaas.cn/article/16319) **Published:** 2022-01-06T02:11:05 **Author:** 5201314 **Excerpt:** 微信小程序如何生成二维码?下面本篇给大家介绍一下利用小程序的canvas能力绘制二维码的方法,希望对大家有所帮… 微信小程序如何生成二维码?下面本篇给大家介绍一下利用小程序的canvas能力绘制二维码的方法,希望对大家有所帮助! ![](https://img.php.cn/upload/article/000/000/024/61d64ee89d288417.jpg) 在微信小程序的业务中会有一些需要展示二维码的场景。静态二维码可以直接存放在本地,使用图片方式展示,但不适合根据用户相关信息生成动态的二维码。本文将介绍下利用小程序的canvas能力绘制二维码。 ## 1 方法一:通过`wx-qr`直接生成 **1.1 DEMO** 微信开发者工具打开查看 | | | | | --- | --- | --- | | ![](https://img.php.cn/upload/image/414/636/607/1641434319281933.png)含背景图 | ![](https://img.php.cn/upload/image/278/257/442/1641434328678342.png)含logo | ![](https://img.php.cn/upload/image/871/396/214/1641434334765322.png)含logo+背景图 | **1.2 安装** \# 通过 npm 安装 npm i wx-qr -S # 通过 yarn 安装 yarn add wx-qr **1.3 使用组件** 首先在你所开发的小程序根目录 `app.json` 或需要使用该组件的 `xxx.json` 中引用组件 (注意:请不要将组件命名为 `wx-xxx` 开头,可能会导致微信小程序解析 tag 失败 ) { "usingComponents": { "qr-container": "wx-qr" } } 之后就可以在 `wxml` 中直接使用组件 Page({ data: { qrTxt: 'https://github.com/liuxdi/wx-qr', }, }); 当然,还可以支持很多种配置,详见github 或者 码云文档。 ## 2\. 方式二:基于QRCode.js结合canvas绘制 **2.0 二维码的组成部分** > ![](https://img.php.cn/upload/image/440/481/331/1641434408535873.png) > > ##### 定位图案 > > - Position Detection Pattern是定位图案,用于标记二维码的矩形大小。这三个定位图案有白边叫Separators for Postion Detection Patterns。之所以三个而不是四个意思就是三个就可以标识一个矩形了。 > > - Timing Patterns也是用于定位的。原因是二维码有40种尺寸,尺寸过大了后需要有根标准线,不然扫描的时候可能会扫歪了。 > > - Alignment Patterns 只有Version 2以上(包括Version2)的二维码需要这个东东,同样是为了定位用的。 > > > ##### 功能性数据 > > - Format Information 存在于所有的尺寸中,用于存放一些格式化数据的。 > > - Version Information 在 >= Version 7以上,需要预留两块3 x 6的区域存放一些版本信息。 > > > ##### 数据码和纠错码 > > - 除了上述的那些地方,剩下的地方存放 Data Code 数据码 和 Error Correction Code 纠错码。 **2.1 引入二维码数据生成库** 复制qrcode.js至你的小程序相应目录。 **2.2 小程序中建立canvas标签,并给canvas设置长宽** **2.3获取canvas实例及上下文** const query = this.createSelectorQuery(); let dpr = wx.getSystemInfoSync().pixelRatio; query.select('#qr').fields({ node: true, size: true, id: true }) .exec((res) => { let { node: canvas, height, width } = res\[0\]; let ctx = canvas.getContext('2d'); canvas.width = width \* dpr canvas.height = height \* dpr ctx.scale(dpr, dpr); }) **2.4 定义一些变量及绘制二维码的数据码区** 其中**QRCodeModel**是从qrCode.js中导入的 // 二维码的颜色 const colorDark = '#000'; // 获取二维码的大小,因css设置的为750rpx,将其转为px const rawViewportSize = getPxFromRpx(750); // 二维码容错率{ L: 1, M: 0, Q: 3, H: 2 } const correctLevel = 0; // 创建二维码实例对象,并添加数据进行生成 const qrCode = new QRCodeModel(-1, correctLevel); qrCode.addData(url); qrCode.make(); // 每个方向的二维码数量 const nCount = qrCode.moduleCount; // 计算每个二维码方块的大小 const nSize = getRoundNum(rawViewportSize / nCount, 3) // 每块二维码点的大小比例 const dataScale = 1; // 计算出dataScale不为1时,每个点的偏移值 const dataXyOffset = (1 - dataScale) \* 0.5; // 循环行列绘制数据码区 for (let row = 0; row < nCount; row++) { for (let col = 0; col < nCount; col++) { // row 和 col 处的模块是否是黑色区 const bIsDark = qrCode.isDark(row, col); // 是否是二维码的图案定位标识区 Position Detection Pattern(如本模块,是三个顶点位置处的大方块) const isBlkPosCtr = (col < 8 && (row < 8 || row >= nCount - 8)) || (col >= nCount - 8 && row < 8); // 是否是Timing Patterns,也是用于协助定位扫描的 const isTiming = (row == 6 && col >= 8 && col <= nCount - 8) || (col == 6 && row >= 8 && row <= nCount - 8); // 如果是这些区域 则不进行绘制 let isProtected = isBlkPosCtr || isTiming; // 计算每个点的绘制位置(left,top) const nLeft = col \* nSize + (isProtected ? 0 : dataXyOffset \* nSize); const nTop = row \* nSize + (isProtected ? 0 : dataXyOffset \* nSize); // 描边色、线宽、填充色配置 ctx.strokeStyle = colorDark; ctx.lineWidth = 0.5; ctx.fillStyle = bIsDark ? colorDark : "rgba(255, 255, 255, 0.6)"; // 如果不是标识区,则进行绘制 if (!isProtected) { ctx.fillRect( nLeft, nTop, (isProtected ? (isBlkPosCtr ? 1 : 1) : dataScale) \* nSize, (isProtected ? (isBlkPosCtr ? 1 : 1) : dataScale) \* nSize ); } } } 此时已经绘制出二维码的数据码区: ![](https://img.php.cn/upload/image/103/900/786/1641434416683001.png) **2.5 绘制图形识别区** // 绘制Position Detection Pattern ctx.fillStyle = colorDark; ctx.fillRect(0, 0, 7 \* nSize, nSize); ctx.fillRect((nCount - 7) \* nSize, 0, 7 \* nSize, nSize); ctx.fillRect(0, 6 \* nSize, 7 \* nSize, nSize); ctx.fillRect((nCount - 7) \* nSize, 6 \* nSize, 7 \* nSize, nSize); ctx.fillRect(0, (nCount - 7) \* nSize, 7 \* nSize, nSize); ctx.fillRect(0, (nCount - 7 + 6) \* nSize, 7 \* nSize, nSize); ctx.fillRect(0, 0, nSize, 7 \* nSize); ctx.fillRect(6 \* nSize, 0, nSize, 7 \* nSize); ctx.fillRect((nCount - 7) \* nSize, 0, nSize, 7 \* nSize); ctx.fillRect((nCount - 7 + 6) \* nSize, 0, nSize, 7 \* nSize); ctx.fillRect(0, (nCount - 7) \* nSize, nSize, 7 \* nSize); ctx.fillRect(6 \* nSize, (nCount - 7) \* nSize, nSize, 7 \* nSize); ctx.fillRect(2 \* nSize, 2 \* nSize, 3 \* nSize, 3 \* nSize); ctx.fillRect((nCount - 7 + 2) \* nSize, 2 \* nSize, 3 \* nSize, 3 \* nSize); ctx.fillRect(2 \* nSize, (nCount - 7 + 2) \* nSize, 3 \* nSize, 3 \* nSize); // 绘制Position Detection Pattern 完毕 // 绘制Timing Patterns const timingScale = 1; const timingXyOffset = (1 - timingScale) \* 0.5; for (let i = 0; i < nCount - 8; i += 2) { \_drawDot(ctx, 8 + i, 6, nSize, timingXyOffset, timingScale); \_drawDot(ctx, 6, 8 + i, nSize, timingXyOffset, timingScale); } // 绘制Timing Patterns 完毕 这时候,一个朴素的二维码就绘制成功啦~ ![](https://img.php.cn/upload/image/301/413/586/1641434422913735.png) > 具体代码详见微信小程序代码片段 > > https://developers.weixin.qq.com/s/WHJj73mX7bwv 该代码只是提供了一个简单二维码的生成逻辑。若需要更复杂的二维码展示功能,还是建议使用wx-qr或参考里面的具体代码。欢迎各位提Issue和Star~~ 【相关学习推荐:小程序开发教程】 以上就是如何利用小程序的canvas来绘制二维码?的详细内容,更多请关注知企PROSAAS其它相关文章! **Categories:** 后端开发 ---