VUE生成批量生产二维码(太阳码)并压缩下载,微信扫一扫或者小程序内扫一扫

本文讲述了在一个租车场景中,如何利用微信扫一扫功能,通过前端展示和处理后端返回的太阳码base64字符串,使用JSZip和file-saver库进行批量二维码下载,以及小程序端如何处理扫码事件的过程。
摘要由CSDN通过智能技术生成

项目需求

租车场景:需要用户使用微信扫一扫直接打开小程序,携带车辆参数。

界面展示

前景颜色就是文字的样子,背景颜色就是整体背景色、把正方的太阳码图片裁剪成圆形方法中有实现过程(注:我没有看详细看文档不知道能否生成圆形的图片,我的后端是给我我一个正方的╮(╯▽╰)╭ )。
请添加图片描述

整体架构流程

前端使用到了jszip、file-saver俩个包需要要自行下载
由于这是服务器那边去微信换取多个二维码(太阳码),然后返回过来再处理。所以取到的值就是一个太阳码的base64格式的字符串。
我这里是传给后端数量,后端生成好统一返还过来了。如果您的后端告你需要一个个换取的话,获取哪里自行改成循环即可,也很简单。
由于太阳码只能小程序调用接口生成,如果想要自己生成的二维码的话,自行下载qrcode然后根据参数自行生成二维码,循环即可。

上代码

弹框的样式代码

<!-- 二维码下载前设置弹框 -->
<el-dialog
      :title="title"
      :visible.sync="openDataScope"
      width="1000px"
      append-to-body
      center
    >
      <el-row>
        <el-col :span="12">
          <div class="qrcode_title">二维码预览</div>
          <div class="qrcode_box">
            <img
              class="qrcode_canvas"
              id="qrcode_canvas"
              ref="qrcode_canvas"
              alt="二维码"
            />
            <canvas
              v-show="false"
              :width="qrSize"
              :height="qrSize"
              class="canvas"
              ref="canvas"
            ></canvas>
          </div>
        </el-col>
        <el-col :span="12">
          <div class="qrcode_title">设置</div>
          <el-form :model="codeForm" label-width="100px">
            <el-row>
              <el-col :span="12">
                <el-form-item label="前景颜色">
                  <el-color-picker
                    @change="setColor"
                    v-model="codeForm.frontColor"
                  ></el-color-picker>
                </el-form-item>
              </el-col>
              <el-col :span="12">
                <el-form-item label="背景颜色">
                  <el-color-picker
                    @change="setColor"
                    v-model="codeForm.backColor"
                  ></el-color-picker>
                </el-form-item>
              </el-col>
            </el-row>
            <el-row>
              <el-form-item label="下载数量">
                <el-input-number
                  v-model="codeForm.num"
                  :min="1"
                  :max="100"
                  label="二维码数量"
                ></el-input-number>
              </el-form-item>
            </el-row>
          </el-form>
        </el-col>
      </el-row>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitDataScope">下载</el-button>
        <el-button @click="cancelDataScope">取 消</el-button>
      </div>
    </el-dialog>

用到的变量

data() {
    return {
    	codeForm: {
	        id: null,
	        frontColor: "#FFFFFF",
	        backColor: "#28A7A7",
	        num: 1,
	      },
	      qrSize: 400,
	      qrTextSize: 16,
	      codeImgList: [],
	      ceishiQrLogo:'', // 这个就放预览时的base64格式的图片
    }
}

实现方法

// 设置前景色或者后景色重绘二维码
	setColor() {
      this.initCanvasImg();
    },
    initCanvasImg(arText, qrLogo) {
    
      arText = arText ? arText : "202401010001";
      let topText = "微信搜索“****”小程序"; //顶部文字
      let qrcode_canvas = this.$refs.qrcode_canvas;
      let canvas = this.$refs.canvas;
      let ctx = canvas.getContext("2d");
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      ctx.fillStyle = this.codeForm.backColor;
      ctx.fillRect(0, 0, canvas.width, canvas.height);
      var image = new Image();
      image.src = qrLogo ? qrLogo : this.ceishiQrLogo;
      image.onload = () => {
        ctx.save();
        ctx.beginPath();
        ctx.fillStyle = "#FFFFFF";
        ctx.arc(200, 200, 140, 0, Math.PI * 2, false);
        ctx.fill();
        ctx.clip();
        ctx.drawImage(image, 80, 80, 240, 240);
        ctx.restore();
      };
      // ctx.save(); ctx.clip(); ctx.restore(); 共同实现了把图片裁剪成圆形显示。
	
       //设置底部编码
      if (arText) {
        ctx.font = "bold " + this.qrTextSize + "px Arial";
        let tw = ctx.measureText(arText).width; //文字真实宽度
        let ftop = this.qrSize - this.qrTextSize - 20; //根据字体大小计算文字top
        let fleft = (this.qrSize - tw) / 2; //根据字体大小计算文字left
        let tp = this.qrTextSize / 2; //字体边距为字体大小的一半
        ctx.fillStyle = this.codeForm.backColor;
        ctx.fillRect(
          fleft - tp / 2,
          ftop - tp / 2,
          tw + tp,
          this.qrTextSize + tp
        );
        ctx.textBaseline = "top"; //绘制文本时的文本基线
        ctx.fillStyle = this.codeForm.frontColor;
        ctx.fillText(arText, fleft, ftop); //canvas填充文字
      }
      //设置顶部提示
      if (topText) {
        ctx.font = "bold " + this.qrTextSize + "px Arial";
        let tw = ctx.measureText(topText).width; //文字真实宽度
        let ftop = 25;
        let fleft = (this.qrSize - tw) / 2; //根据字体大小计算文字left
        let tp = this.qrTextSize / 2; //字体边距为字体大小的一半
        ctx.fillStyle = this.codeForm.backColor;
        ctx.fillRect(
          fleft - tp / 2,
          ftop - tp / 2,
          tw + tp,
          this.qrTextSize + tp
        );
        ctx.textBaseline = "top"; //绘制文本时的文本基线
        ctx.fillStyle = this.codeForm.frontColor;
        ctx.fillText(topText, fleft, ftop); //canvas填充文字
      }
	
		//同步执行时图片会丢失,需要异步
      setTimeout(() => {
        qrcode_canvas.src = canvas.toDataURL("image/jpeg");
        this.codeImgList.push({
          code: arText,
          imgBase: canvas.toDataURL(),
        });
      }, 10);
    },
// base64 转 二进制流(blob)
    dataURLtoBlob(dataurl) {
      var arr = dataurl.split(","),
        mime = arr[0].match(/:(.*?);/)[1],
        bstr = atob(arr[1]),
        n = bstr.length,
        u8arr = new Uint8Array(n);
      while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
      }
      return new Blob([u8arr], {
        type: mime,
      });
    },
    /** 下载二维吗 */
    submitDataScope() {
      vehicleAdd({
        vehicleId: this.codeForm.id,
        num: this.codeForm.num,
      }).then((response) => {
        this.codeImgList = [];
        for (let i = 0; i < response.rows.length; i++) {
          let qrLogo = "data:image/png;base64," + response.rows[i].url;
          this.initCanvasImg(response.rows[i].showCode, qrLogo);
        }

        const loading = this.$loading({
          lock: true,
          text: "正在生成二维码,请勿刷新页面",
          spinner: "el-icon-loading",
          background: "rgba(0, 0, 0, 0.7)",
        });

        setTimeout(() => {
          let zip = new JSZip();
          let index = 0;
          for (let k = 0; k < this.codeImgList.length; k++) {
            index++;
            console.log(this.codeImgList[k]);
            let blob = this.dataURLtoBlob(this.codeImgList[k].imgBase); //转二进制
            // let blob = this.codeImgList[k].imgBase;
            zip.file(this.codeImgList[k].code + ".png", blob, { blob: true }); //图片名称(这里以编号命名)
            if (index === this.codeImgList.length) {
              zip.generateAsync({ type: "blob" }).then(
                (blob) => {
                  FileSaver.saveAs(blob, "车辆二维码.zip"); //下载之后的文件名
                  this.openDataScope = false;
                  loading.close();
                },
                (err) => {
                  loading.close();
                  consle.log(err);
                }
              );
            }
          }
        }, 2000);
      });
    },

小程序端取到参数

由于项目要求,用户不仅可以通过微信扫一扫进入,还可以在小程序内部的扫码。
所以接收就出出现两种形式
在这里插入图片描述

		// 第一种:用户通过微信扫一扫进来的
		onLoad(query) {
			let scene = decodeURIComponent(query.scene)
			if(scene != "undefined"){
				uni.setStorageSync('sceneCode',scene)
				// scene 就是值,后续逻辑根据场景使用自行处理
			}
		},
		
		// 第二种:用户在小程序内扫码
		scanCode() {
				uni.scanCode({
					onlyFromCamera: true,
					success: res => {
						let scene = decodeURIComponent(res.path.split('=')[1])
						// scene 就是值。后续逻辑根据场景使用自行处理
					}
				});
			},


总结

整体都是拼接而成的,感谢各位大佬放出的代码。

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

静的小白菜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值