因为微信小程序只能分享给好友,所以想在朋友圈传播,只能通过生成一张带二维码的图片,用户主动将图片分享到朋友圈实现。
需求:
生成一张带用户头像和小程序码拼合在一起的的图片。
坑点:
- 官方提供的小程序码的4个接口中,小程序二维码文档,只有b接口生成数量不受限,但是可传参数长度最大32字符。
- 需求中用户头像需覆盖二维码,在绘制分享图片前,要先生成圆形的用户头像。
- canvas不能被隐藏,否则会生成空图片。
- 绘制canvas后不能马上转为图片,否则有一定概率生成未绘制完成的图片。
- 部分机型上图片过大会默认展示压缩图,微信无法识别压缩图上的二维码。
- canvas上的文字超出一行无法自动换行,且微信提供的测量文案长度的api有最低版本要求,所以要求文案尽量简略。
- canvas的drawImage方法无法绘制网络图片,需先行通过downloadFile下载到本地再绘制到canvas。
实现流程:
- 下载小程序码 和 绘制圆形用户头像
- 绘制分享图
- 将canvas转换成图片并展示。
wxml部分代码:
<canvas class="canvas-qrcode" canvas-id="qrcode" />
css部分:
- canvas的宽高、位置要根据具体实现的图片样式而异。
- 要通过定位的方式隐藏canvas,而不能display: none;,否则生成的图片会是空白的。
.canvas-qrcode {
position: absolute;
top: -800px;
left: 0;
width: 750px;
height: 750px;
}
js部分
// 点击生成图片按钮
handleQrcodeTap() {
Promise
.all([this.drawAvatar(), this.requestQrcode()])
.then(this.drawCanvas)
.catch(() => {
// 失败提示
});
}
// 生成圆形头像
drawAvatar() {
return new Promise(function (resolve, reject) {
wx.downloadFile({
url: 用户头像url,
success: (res) => {
if (res.statusCode === 200 && res.errMsg === 'downloadFile:ok' && res.tempFilePath && !res.tempFilePath.match(/\.html?$/i)) {
// 通过剪裁实现圆形头像,save -> clip -> restore不能省略
const ctx = wx.createCanvasContext('qrcode');
ctx.save();
ctx.arc(50, 50, 50, 0, 2 * Math.PI);
ctx.clip();
ctx.drawImage(res.tempFilePath, 0, 0, 100, 100);
ctx.restore();
ctx.draw(false, function() {
setTimeout(function () {
wx.canvasToTempFilePath({
canvasId: 'qrcode',
x: 0,
y: 0,
width: 100,
height: 100,
success(res) {
resolve(res.tempFilePath);
},
fail() {
reject();
},
});
}, 300);
});
} else {
reject();
}
},
fail() {
reject();
},
});
})
}
// 获取小程序码
requestQrcode() {
return new Promise(function (resolve, reject) {
wx.downloadFile({
url: 二维码图片,
success(res) {
if (res.statusCode === 200 && res.errMsg === 'downloadFile:ok' && res.tempFilePath && !res.tempFilePath.match(/\.html?$/i)) {
resolve(res.tempFilePath);
} else {
reject();
}
},
fail() {
reject();
},
});
})
}
// 绘制分享图
drawCanvas() {
ctx.draw(false, function() {
// 延迟生成图片
setTimeout(function () {
wx.canvasToTempFilePath({
canvasId: 'qrcode',
width: 750,
height: 750,
quality: 0.9, // 生成jpg格式并调低质量
fileType: 'jpg',
success:(res) {
wx.previewImage({
urls: [res.tempFilePath],
});
},
fail() {
wx.hideLoading();
},
});
}, 300);
});
}
待优化部分
每一步生成图片的临时地址都可以缓存下来,这样在当前页面再绘制分享图的时候就不需要重新绘制、重新下载,可以大大节省二次绘制的时间,我们在项目里也是这样做的。因为这只是demo,为了减少代码量,去掉了优化缓存部分。