1:生成臨時圖片,保證畫布被加載以及渲染(即自己不能夠 hidden 或是 上級元素不能夠 hidden 或是 wx:if 隱藏等)javascript
== 》 建議:由於 canvas 的組件層級(z-index)是最高的,沒法經過層級改變,如自定義的彈框相似的組件總會被擋住 css
== 》 若不想給擋住,便要控制 canvas 隱藏(hidden 、 wx:if)java
可是利用 API ctx.setGlobalAlpha = 0(只是變成不透明,視覺上給隱藏,可是仍是還在,如果那位置有 tap 等事件就尷尬了)jquery
== 》 由於我只是利用 canvas生成二維碼圖片, swiper 輪播等使用,必需要二維碼圖片。ios
+++++ 諸多使用把canvas生成的二維碼生成圖片緣由緣由canvas
1:我自定義使用 alert 、confirm、message組件,由於canvas 組件由客戶端native生成,改變不了層級,api
因此老是總之 隱藏好麻煩,也解決不了我使用輪播使用二維碼 app
2:官網(CSS動畫對canvas無效)框架
tip
: canvas
組件是由客戶端建立的原生組件,它的層級是最高的,不能經過 z-index 控制層級。 tip
: 請勿在 scroll-view
、swiper
、picker-view
、movable-view
中使用 canvas
組件。 tip
: css
動畫對 canvas
組件無效。 bug
: 避免設置過大的寬高,在安卓下會有crash的問題
解決的方法:iphone
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 的坑,你看到這裏,這些坑你也在踩,恰好我踩過了,給大家參考,但願對大家有幫助!