微信小程序生成多张二维码以及支持async await
需求来了
最近项目需要在列表里生成微信二维码,之前用的是qrcode.js,但是只是用于生成一张图片。这次网上搜了下插件,很多也都用qrcode.js,我找了个别的插件,base64-weapp-qrcode.js,使用了一下,效果很不好,决定还是用回qrcode.js。
这里要说明一点,网上看了下很多案例,基本都要使用setTimeout()延迟来接收绘制后的图片路径。这样做不太好,第一想一次性绘制多张二维码的话,实现比较麻烦,第二,我们没法确保setTimeout里面的函数执行的时候二维码一定生成好了。
不过没关系,把插件改改就好了。
原生小程序实现支持async await
想要方便的实现在列表里面绘制多张二维码,首先得让你的微信小程序支持async await,这首先得用到runtime.js插件,git 地址:https://github.com/facebook/regenerator/blob/master/packages/regenerator-runtime/runtime.js,下下来以后,将runtime.js放到你的项目中(一般可以放到utils文件夹里面),然后页面通过import 引入即可
import regeneratorRuntime from '../../utils/regenerator-runtime/runtime.js'
这里需要注意的一点是,你引入这个包后可能包会报错,这个时候找到runtime.js,翻到最下面,将try{}catch(){}部分注释掉即可。
qrcode.js中引入runtime.js
接下来对qrcode.js进行改造,首先要引入runtime.js。
import regeneratorRuntime from '../regenerator-runtime/runtime.js'
然后找到 qrcode.js里面的draw函数,更改如下
draw: function (config) {
//这里顺便把背景颜色,二维码颜色也做成参数,如果需要可以改变二维码颜色。由于参数数量增多,而且有多个并非必须参数,因此改为对象,方便取值。
let { value, canvasId, cavW, cavH, $this, ecc, bkColor = '#ffffff', codeColor = '#000000' } = config
var that = this;
ecclevel = ecc || ecclevel;
canvasId = canvasId || _canvas;
if (!canvasId) {
console.warn('No canvas provided to draw QR code in!')
return;
}
var size = Math.min(cavW, cavH);
value = that.utf16to8(value);//增加中文显示
var frame = that.getFrame(value),
// 组件中生成qrcode需要绑定this
ctx = wx.createCanvasContext(canvasId, $this),
px = Math.round(size / (width + 8));
var roundedSize = px * (width + 8),
offset = Math.floor((size - roundedSize) / 2);
size = roundedSize;
ctx.clearRect(0, 0, cavW, cavW);
ctx.setFillStyle(bkColor)
ctx.fillRect(0, 0, cavW, cavW);
ctx.setFillStyle(codeColor);
for (var i = 0; i < width; i++) {
for (var j = 0; j < width; j++) {
if (frame[j * width + i]) {
ctx.fillRect(px * (4 + i) + offset, px * (4 + j) + offset, px, px);
}
}
}
//这里也是关键,需要让函数返回一个promise对象,方便使用是使用await 接收
return new Promise((resolve, reject) => {
// console.log(canvas)
/*ctx.draw可以接收两个参数,第一个参数是是否保留上一次的绘制结果,true为保留,false为不保留,这里选择不保留;
第二个参数是绘制完成以后的回调函数,这里在绘制完成以后的回调函数里面,调用小程序的wx.canvasToTempFilePath API,直接获取到图片路径,并用resolve返出*/
ctx.draw(false, function () {
wx.canvasToTempFilePath({
canvasId,
success: function (res) {
// console.log(res)
let tempFilePath = res.tempFilePath;
// console.log(tempFilePath)
resolve(tempFilePath)
},
fail: function (res) {
console.log(res)
}
})
})
})
}
qrcode.js改造完成。
使用
在使用页面js文件引入qrcode.js
const QR = require('../../utils/externalUtils/qrcode.js')
从服务器请求到数据以后,循环调用qrcode的api,生成多张二维码,并将路径存储在数组中。这里注意传入的cavW 和cavH最好和canvas标签里设置的相同
let noUserdCards=await this.getNoUsedMyCards()
for (let i = 0; i < noUserdCards.length; i++) {
let imagePath = await QR.api.draw({ value: noUserdCards[i].qrcode, canvasId: "myCardCanvas", cavW: 300, cavH: 300, })
noUserdCards[i].imagePath = imagePath
}
this.setData({
renderCards: noUserdCards
})
在使用页面wxml里面加上canvas标签
<!-- 二维码canvas -->
<view class="canvas-box">
<canvas style="width: 300px;height: 300px;background:#f1f1f1;" canvas-id="myCardCanvas" />
</view>
由于canvas标签只用于绘制二维码,不需要给客户看,真正给客户看的是绘制好的图片。所有使用窗口绝对定位将canvas标签扔到看不见的地方,切记不可以使用wx:if或者hidden来显示隐藏canvas,会有很多让你痛苦的坑,而且这样你基本拿不到canvas 对象
/*二维码canvas*/
.canvas-box {
position: fixed;
right: -100%;
top: -100%;
}
至此,对qrcode.js的改造完成。
此次改造还有个遗憾,就是想加入支持带logo图片,目前尚未成功,求各位大神指点。