1:生成临时图片,保证画布被加载以及渲染(即本身不可以 hidden 或是 上级元素不可以 hidden 或是 wx:if 隐藏等)
== 》 建议:因为 canvas 的组件层级(z-index)是最高的,无法通过层级改变,如自定义的弹框类似的组件总会被挡住
== 》 若不想给挡住,便要控制 canvas 隐藏(hidden 、 wx:if)
但是利用 API ctx.setGlobalAlpha = 0(只是变成不透明,视觉上给隐藏,但是还是还在,若是那位置有 tap 等事件就尴尬了)
== 》 因为我只是利用 canvas生成二维码图片, swiper 轮播等使用,必须要二维码图片。
+++++ 诸多使用把canvas生成的二维码生成图片原因原因
1:我自定义使用 alert 、confirm、message组件,因为canvas 组件由客户端native生成,改变不了层级,
所以总是总之 隐藏好麻烦,也解决不了我使用轮播使用二维码
2:官网(CSS动画对canvas无效)
tip
:canvas
组件是由客户端创建的原生组件,它的层级是最高的,不能通过 z-index 控制层级。tip
: 请勿在scroll-view
、swiper
、picker-view
、movable-view
中使用canvas
组件。tip
:css
动画对canvas
组件无效。bug
: 避免设置过大的宽高,在安卓下会有crash的问题
解决的方法:
a:把 需要的 canvas 单独显示在屏幕外的十万八千里之外(position:fixed;top:-1000px;left:-1000px)
=》单独 单独 单独 啊 不要有父级元素(反正是用生成图片用)
注意了:保证 canvas 的 宽高与 生成二维码的宽高参数保持一致
1 <canvas canvas-id="QRCode-canvas-0" style="width:{{SIZE}}px;height:{{SIZE}}px;position: fixed;left: -500px; bottom: -500px;"></canvas>
b:利用插件(网上很多说明 jquery-qrcode.js插件)自己参考修改成 wx 的接口的;如 使用 wepy框架 ES6语法
import {
QRCode,
QRErrorCorrectLevel
} from \'./qrcode\';
import wepy from \'wepy\';
export default class QRCodeMixin extends wepy.mixin {
data = {
//设置画布大小
SIZE: 0,
};
async setSize(customSize = 150) {
const res = await wepy.getSystemInfoSync();
console.log(\'获取系统信息:*************** \', res)
//不同屏幕下canvas的适配比例;设计稿是750宽
// iphone6 => 180 px deviceWidth 375px
const scale = 375 / customSize;
const width = res.windowWidth / scale;
return parseInt(width);
};
async drawQRCode(ops = {}) {
console.time(\'+++++++++++ 画布绘制总耗时:\');
const DEFAULT = {
render: \'canvas\', //设置渲染方式 (有两种方式 table和canvas,默认是canvas)
typeNumber: 6, //计算模式
background: \'#ffffff\', //背景颜色
foreground: \'#1A1A1A\', //前景颜色
correctLevel: QRErrorCorrectLevel.H, //纠错等级 QRErrorCorrectLevel.H, =》 L 、M 、Q 、R、 H
canvasId: \'QRCode-canvas\', //canvas对象 id
text: \'QR-Code\' //生成二维码的内容
};
let options = Object.assign({}, DEFAULT, {
width: ops.size,//保持输入的宽高与canvas组件的宽高一致
height: ops.size
}, ops);
if (!options.canvasId || options.canvasId == \'\') {
throw new Error(\'请输入有效的画布 id !\')
return false;
}
const createCanvas = async(options) => {
// create the qrcode itself
const qrcode = new QRCode(options.typeNumber, options.correctLevel);
qrcode.addData(options.text);
qrcode.make();
// get canvas context
const ctx = wx.createCanvasContext(options.canvasId);
console.log(\'++++++++++++++ 当前画布对象:\', ctx);
// compute tileW/tileH based on options.width/options.height
const tileW = options.width / qrcode.getModuleCount();
const tileH = options.height / qrcode.getModuleCount();
//保存当前的绘图上下文
ctx.save();
// draw in the canvas
for (let row = 0; row < qrcode.getModuleCount(); row++) {
for (let col = 0; col < qrcode.getModuleCount(); col++) {
let style = qrcode.isDark(row, col) ? options.foreground : options.background;
ctx.setFillStyle(style);
let w = (Math.ceil((col + 1) * tileW) - Math.floor(col * tileW));
let h = (Math.ceil((row + 1) * tileW) - Math.floor(row * tileW));
ctx.fillRect(Math.round(col * tileW), Math.round(row * tileH), w, h);
}
};
//恢复之前保存的绘图上下文。
ctx.restore();
ctx.draw(true, () => {
//一定要延时一下,总是不延时,我本人的手机生成的二维码还是图片有bug
了
setTimeout(() => {
wepy.canvasToTempFilePath({
canvasId: options.canvasId,
quality: 0.9,
x: 0,
y: 0,
width: options.width,
height: options.height,
}).then(res => {
options.callback && options.callback(res.tempFilePath);
console.log(\'++++++++++++++++ wx.canvasToTempFilePath:\', res);
});
}, 700);
);
});
};
createCanvas(options);
};
};
生成临时图片关键的一步:
1 ctx.draw(true, () => { 2 setTimeout(() => { 3 wepy.canvasToTempFilePath({ 4 canvasId: options.canvasId, 5 quality: 0.9, 6 x: 0, 7 y: 0, 8 width: options.width, 9 height: options.height, 10 }).then(res => { 11 options.callback && options.callback(res.tempFilePath); 12 console.log(\'++++++++++++++++ wx.canvasToTempFilePath:\', res); 13 14 }); 15 }, 700); 16 17 });
不懂参考官网 API 说明:https://developers.weixin.qq.com/miniprogram/dev/api/
把混合的模块加载对应的Page 上,使用
//把二维码生成图片
const self = this; this.drawQRCode({ text: ticketNo, size, callback(tempFilePath) { //把二维码生成图片 self.QRCodeFilePath = tempFilePath; self.$apply(); } });
// tempFilePath 就是上面 QRCodeMixin 封装好的生成的临时图片,再用 data 接收
生成的图片:
坑1:刚开始经常遇到 andriad 机器生成图片白色的什么内容也没有(ios就正常) (因为没有在 wx.draw 后的回调调用)
坑2:控制台打印:canvas 为空 =》 就是上级或是本身给隐藏了(hidden 或是 wx:if)
坑3:生成的临时图片有时候正常有时候不正常(开发工具都正常的),真机就遇到 ,后来在 延时一下再执行 wepy.canvasToTempFilePath
坑4:轮播图本来用一个 canvas 画图并导出图片,可是有时候有bug的,有些二维码不正常的(所以我是用了三个 canvas 组件,递归执行完,很完美的图片出来,虽然用了三个看起来臃肿,本来使用 swier 触发再对应渲染的内容后再生成图片的)
<canvas canvas-id="QRCode-canvas-0" style="width:{{SIZE}}px;height:{{SIZE}}px;position: fixed;left: -500px; bottom: -500px;"></canvas> <canvas canvas-id="QRCode-canvas-1" style="width:{{SIZE}}px;height:{{SIZE}}px;position: fixed;left: -50px; bottom: -1000px;"></canvas> <canvas canvas-id="QRCode-canvas-2" style="width:{{SIZE}}px;height:{{SIZE}}px;position: fixed;left: -50px; bottom: -1500px;"></canvas>
生成图片
async draw(indexValidTicketList) { const self = this; //把二维码生成图片 self.drawQRCode({ canvasId: \'QRCode-canvas-\' + self.DRAW_QRCODE_INDEX, text: indexValidTicketList[self.DRAW_QRCODE_INDEX].ticketNo, size: self.SIZE, callback(tempFilePath) { //把二维码生成图片 indexValidTicketList[self.DRAW_QRCODE_INDEX][\'QRCodeFilePath\'] = tempFilePath; self.$apply(); // self.DRAW_QRCODE_INDEX++; //最多显示三张 if (self.DRAW_QRCODE_INDEX < indexValidTicketList.length) { self.draw(indexValidTicketList); } else { self.DRAW_QRCODE_INDEX = 0; self.$apply(); } } }); };
能成功生成一张图片,至于多张图片你们自己觉得合理的方法去实现,这次 用 canvas 的坑,你看到这里,这些坑你也在踩,刚好我踩过了,给你们参考,希望对你们有帮助!