小程序canvas生成二維碼圖片踩的坑

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無效)框架

  •  tipcanvas 組件是由客戶端建立的原生組件,它的層級是最高的,不能經過 z-index 控制層級。
  •  tip: 請勿在 scroll-viewswiperpicker-viewmovable-view 中使用 canvas 組件。
  •  tipcss 動畫對 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 的坑,你看到這裏,這些坑你也在踩,恰好我踩過了,給大家參考,但願對大家有幫助!

相關文章
相關標籤/搜索