小程序canvas生成二维码图片踩的坑

摘要:
1: 生成临时图像以确保画布被加载和渲染(即,画布本身无法隐藏或父元素无法隐藏或wx:if hidden)==˃建议:因为画布的组件级别(z索引)是最高的,所以不能通过级别更改。例如,自定义弹出框等组件总是被阻止==˃如果不想阻止,则需要控制画布的隐藏(隐藏,wx:If),但使用APIctx。setGlobalAlpha=0(只是变得不透明,可见

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无效)

  •  tipcanvas 组件是由客户端创建的原生组件,它的层级是最高的,不能通过 z-index 控制层级。
  •  tip: 请勿在 scroll-viewswiperpicker-viewmovable-view 中使用 canvas 组件。
  •  tipcss 动画对 canvas 组件无效。
  •  bug: 避免设置过大的宽高,在安卓下会有crash的问题

解决的方法:

a:把 需要的 canvas 单独显示在屏幕外的十万八千里之外(position:fixed;top:-1000px;left:-1000px)

=》单独 单独 单独 啊 不要有父级元素(反正是用生成图片用)

注意了:保证 canvas 的 宽高与 生成二维码的宽高参数保持一致

1  <canvas canvas-id="QRCode-canvas-0" style="{{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, {
             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,
                         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                          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 接收

 生成的图片:

小程序canvas生成二维码图片踩的坑第1张

坑1:刚开始经常遇到 andriad 机器生成图片白色的什么内容也没有(ios就正常) (因为没有在 wx.draw 后的回调调用)

坑2:控制台打印:canvas 为空 =》 就是上级或是本身给隐藏了(hidden 或是 wx:if)

坑3:生成的临时图片有时候正常有时候不正常(开发工具都正常的),真机就遇到 ,后来在 延时一下再执行 wepy.canvasToTempFilePath

坑4:轮播图本来用一个 canvas 画图并导出图片,可是有时候有bug的,有些二维码不正常的(所以我是用了三个 canvas 组件,递归执行完,很完美的图片出来,虽然用了三个看起来臃肿,本来使用 swier 触发再对应渲染的内容后再生成图片的)

 <canvas canvas-  style="{{SIZE}}px;height:{{SIZE}}px;position: fixed;left: -500px; bottom: -500px;"></canvas>
 <canvas canvas-  style="{{SIZE}}px;height:{{SIZE}}px;position: fixed;left: -50px; bottom: -1000px;"></canvas>
 <canvas canvas-  style="{{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 的坑,你看到这里,这些坑你也在踩,刚好我踩过了,给你们参考,希望对你们有帮助!

免责声明:文章转载自《小程序canvas生成二维码图片踩的坑》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇浅谈C#托管程序中的资源释放问题grafana 8.0 新的报警机制下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

elementui源码解析markdown处理

一些参考网址: markdown-it官网:markdown-it | markdown-it 中文文档 (docschina.org) markdown-it插件的分析和源码分析参考地址:https://zhuanlan.zhihu.com/p/64290806 参考例子:https://gitee.com/springliuliu/mdToHtm...

旋转的太极图

1.创建一个画布,获取canvas节点   <canvas id="c" width="500" height="500"></canvas>//创建canvas节点 <script type="text/javascript"> var canvas = document.get...

duilib之源码分析

《duilib之源码分析》1 stdAfx.h [cpp]view plaincopy *lengthof(x)计算数组长度宏 *MAX两值最大 *MIN两值最小 *CLAMP(x,a,b)x在a,b之间则取x否则取最小 2 UIBase [cpp]view plaincopy *UI_WNDSTYLE_窗口风格属性 *UI_CLASS...

【Ray Tracing The Next Week 超详解】 光线追踪2-7 任意长方体 &amp;amp;&amp;amp; 场景案例

上一篇比较简单,很久才发是因为做了一些好玩的场景,后来发现这一章是专门写场景例子的,所以就安排到了这一篇 Preface 这一篇要介绍的内容有: 1. 自己做的光照例子 2. Cornell box画质问题及优化方案 3. 新的场景几何体——长方体 轴平行长方体 任意长方体 我们这一篇重实践轻理论阐述 ready 1. 需要上一章的知识 但是,上一章的Co...

第四节:Webpack本地服务器搭建、剖析devServer的HRM热替换和其它配置、resolve模块解析、区分开发/生产环境方案实战

一. webpack本地服务器搭建 1. 为什么要搭建本地服务器?  我们之前通过【npm run build】,编译相关的代码; 然后需要在浏览器中运行,每次修改修改代码,都需要重新编译运行,很麻烦。我们希望可以做到,当文件发生变化时,可以自动的完成 编译 和 展示 。 2. watch mode模式 (1). 简介   在该模式下,webpack依赖图...

H5动画开发快车道

前言 以往做一些H5的运营项目,都是动画设计师使用Animate cc(原来的Flash)先设计好动画原型,然后交给我们UI开发来实现。做过动画开发的童鞋都知道动画开发都是比较耗费时间精力的,而且还要高质量的还原动画设计师设计好的动画,来回沟通成本也非常高。 那有没有一种高效的方法来改善这种流程,提高开发效率的同时还能完成高品质的动画呢? 经过一段时间的摸...