vue生成并下载带文字标题的二维码

2023-10-19 10:40 秦倩 1768

前端生成二维码的方式有很多,例如qrcodejs、、vue-qr、node-qrcode、jQuery.qrcode等,本文主要介绍借助node-qrcode+canvas和vue-qr+html2canvas生成带有文字标题的二维码。

一、使用node-qrcode+canvas

node-qrcode

node-qrcode是一个QR码/2d条码生成器。是一个cli实用程序,可以在服务端和客户端上使用,可以将二维码保存为图片,支持数字、字母数字、汉字和字节模式,支持混合模式、支持中文、西里尔文、希腊文和日文字符,支持多字节字符,例如表情符号,能自动生成优化片段,实现最佳数据压缩和最小QR代码尺寸。

概念解释:

1.Error correction level----纠错级别

在二维码部分模糊的情况下依然可以进行识别,分为四个识别等级。级别越高,纠错能力越强,但二维码的容量会降低。如果二维码被损坏的几率较低(例如通过显示屏显示),建议使用低识别等级(L/M)

百分比符号表示无法读取的最大损坏面积。

纠错级别可以通过options.errorCorrectionLevel属性设置,默认值为M。

QRCode.toDataURL('some text', { errorCorrectionLevel: 'H' }, function (err, url) {
  console.log(url)
})

2.QR Code capacity----二维码容量

容量取决于二维码版本和纠错级别,编码模式也会影响可存储的数据量。

二维码版本:即二维码的规格,从1到40不等。版本 1 的模块为 21x21,版本 2 为 25x25,每一版本比前一版本的边增加4个模块,以此类推。版本越高,可存储的数据越多。下表显示了每种编码模式和每个模糊识别等级的最大可存储字符数。

二维码版本可以通过options.version属性设置,如果没有指定版本,将使用更合适的值。除非需要特定版本,否则不需要此选项。

QRCode.toDataURL('some text', { version: 2 }, function (err, url) {
  console.log(url)
})

API

此处只介绍前端常用的三个api,toCanvas()、toDataUrl()、toString()

toCanvas():二维码生成canvas

toDataUrl():生成base64字符串,将图片转换为base64位编码后,图片会跟随代码(html、css、js)一起请求加载,不会再单独进行请求加载;可以防止由于图片路径错误导致图片加载失败的问题。

toString():生成svg二进制字符

Options

属性名 类型 描述 默认值
QR Code options version Number QR 码版本。如果未指定,将计算出更合适的值。
errorCorrectionLevel String 纠错级别:L、M、Q、H M
maskPattern Number 用于屏蔽符号的屏蔽模式。可选值为 0、1、2、3、4、5、6、7。
toSJISFunc Function 内部使用的辅助函数,用于将汉字转换为其移位 JIS 值。如果需要支持汉字模式,请提供此函数。
Renderers options margin Number 二维码的留白编剧 4
scale Number 比例因子。1 表示每个模块 1 个像素(黑点)。 4
small Boolean 仅适用于终端渲染器。输出更小的 QR 代码。 false
width Number 二维码的宽度 #000000ff
color.dark String 二维码的背景色 #000000ff
color.light String 二维码的前景色 #ffffffff

canvas

<canvas> 标签用于通过脚本(通常是 JavaScript)动态绘制图形。

基本用法

1.创建画布

<canvas id="canvas" width="300" height="300"></canvas>

2.获取上下文对象

var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");

3.定义绘制路径

context.beginPath();
context.rect(20, 40, 200, 80);
context.closePath();

4.设置图形属性

context.strokeStyle = '#f00'; // 设置线条样式
context.fillStyle = "#ccc"; // 设置填充样式

5.绘制图形

context.stroke();
context.fill();

二维码实现

安装node-qrcode

npm install qrcode

引入

import QRCode from 'qrcode'

创建画布

<canvas id="QRCode_header" style=" display: block;"></canvas>

绘制canvas

      // 配置options
      let opts = {
        errorCorrectionLevel: "H", //容错级别
        margin: 5, //二维码留白边距
        width: 280, //二维码宽度
        text: "https://www.baidu.com/", //二维码内容
        color: {
          dark: "#333333", //前景色
          light: "#ffffff", //背景色
        }
      }
      // 获取要绘制二维码的DOM节点
      let canvasDom = document.getElementById("QRCode_header");
      // 将获取到的数据画到canvasDom (canvas)上
      const canvas = await QRCode.toCanvas(canvasDom , this.qrUrl, opts);
      
      // 绘制文字标题
      const size = 280 // 二维码高度
      const qrText = '二维码标题' // 二维码标题
      const fontWeight='bold' // 字体-粗体
      const fontSize = 20 // 字体大小
      const tb = 15 // 底部文字上下间距
      const realHeight = size + fontSize + 2*tb // 实际高度
      // 获取画布的上下文对象
      const ctx = canvas.getContext("2d");
      console.log(ctx,'ctx');
      // 获取二维码数据
      const data = ctx.getImageData(0, 0, size, size);
      canvas.setAttribute('height', realHeight); // 重设画布像素高度
      canvas.style.setProperty('height', realHeight + 'px'); // 重设画布实际高度
      ctx.fillRect(0, 0, size, realHeight) // 绘制“已填色”的矩形
      ctx.putImageData(data, 0, 0)// 填充二维码数据
      ctx.font = `{{fontWeight} {{fontSize}px Arial`; // 设置字体格式
      const textWidth = ctx.measureText(qrText).width; // 获取文字真实宽度
      const ftop = size + tb; //文字距顶部位置
      const fleft = (size - textWidth) / 2; //根据字体大小计算文字left
      const textPadding = fontSize / 2; // 设置字体边距 

      ctx.fillStyle = "#fff"; // 设置底部背景色
      ctx.fillRect(0, size, size, realHeight - size); // 底部填充位置
      // 标题文字填充位置
      ctx.fillRect(
          fleft - textPadding / 2, 
          ftop - textPadding / 2,
          textWidth + textPadding,
          fontSize + textPadding
      );
      ctx.textBaseline = "top"; //设置绘制文本时的文本基线。
      ctx.fillStyle = "#333";// 文本颜色
      ctx.fillText(qrText, fleft, ftop); // 文本填充

二、使用vue-qr+html2canvas

vue-qr

安装

npm install vue-qr

引入

import VueQr from 'vue-qr'
{
    ...
    components: {VueQr}
    ...
}

组件常用参数

text 二维码内容,即扫描二维码后跳转的页面
size 二维码大小,宽高相等
margin 二维码图像的外边距,默认20px
bgSrc 嵌入的背景图地址
logoSrc 嵌入至二维码中心的logo地址
logoScale 中间logo的尺寸
dotScale 二维码的点的大小
colorDark 实点的颜色(和colorLight一起设置才有效)
colorLight 空白的颜色(和colorDark一起设置才有效)
autoColor 若为true,背景图的主要颜色将作为实点的颜色,即colorDark,默认true

html2canvas

什么是html2canvas?

html2canvas的作用就是允许我们直接在用户浏览器上拍摄网页或者某一部分的截图。它的屏幕截图是基于DOM的,因此,可能不会100%精确到真实的表示,因为它不会生成实际的屏幕截图,而是基于页面上可用的信息构建屏幕截图。

工作原理

该脚本会遍历所加载页面的 DOM,收集其中所有元素的信息,然后利用这些信息构建页面的表示形式。换句话说,它实际上并不对页面进行截图,而是根据从 DOM 中读取的属性来构建页面的表示形式。因此,它只能正确呈现它所能理解的属性,也就是说,会许多 CSS 属性无法工作。

支持的浏览器

  • Firefox 3.5+
  • Google Chrome
  • Opera 12+
  • IE9+
  • Edge
  • Safari 6+

安装

npm install html2canvas

引入

import html2canvas from 'html2canvas';

用法

html2canvas(element, options);

完整代码

node-qrcode+canvas

<template>
  <div class="home" :gutters="20">
    <canvas id="QRCode_header" style=" display: block;"></canvas>
    <button @click="downloadQRCode">下载</button>
  </div>
</template>

<script>
import QRCode from 'qrcode'
export default {
  data() {
    return {
      qrUrl: ''
    };
  },
  methods: { 
    async getQRCode() {
      this.qrUrl = 'https://www.baidu.com/'
      // 配置options
      let opts = {
        errorCorrectionLevel: "H", //容错级别
        margin: 5, //二维码留白边距
        width: 280, //二维码宽度
        text: "https://www.baidu.com/", //二维码内容
        color: {
          dark: "#333333", //前景色
          light: "#ffffff", //背景色
        }
      }
      // 获取要绘制二维码的DOM节点
      let canvasDom = document.getElementById("QRCode_header");
      // 将获取到的数据画到canvasDom (canvas)上
      const canvas = await QRCode.toCanvas(canvasDom , this.qrUrl, opts);
      
      // 绘制文字标题
      const size = 280 // 二维码高度
      const qrText = '二维码标题' // 二维码标题
      const fontWeight='bold' // 字体-粗体
      const fontSize = 20 // 字体大小
      const tb = 15 // 底部文字上下间距
      const realHeight = size + fontSize + 2*tb // 实际高度
      // 获取画布的上下文对象
      const ctx = canvas.getContext("2d");
      console.log(ctx,'ctx');
      // 获取二维码数据
      const data = ctx.getImageData(0, 0, size, size);
      canvas.setAttribute('height', realHeight); // 重设画布像素高度
      canvas.style.setProperty('height', realHeight + 'px'); // 重设画布实际高度
      ctx.fillRect(0, 0, size, realHeight) // 绘制“已填色”的矩形
      ctx.putImageData(data, 0, 0)// 填充二维码数据
      ctx.font = `{{fontWeight} {{fontSize}px Arial`; // 设置字体格式
      const textWidth = ctx.measureText(qrText).width; // 获取文字真实宽度
      const ftop = size + tb; //文字距顶部位置
      const fleft = (size - textWidth) / 2; //根据字体大小计算文字left
      const textPadding = fontSize / 2; // 设置字体边距 

      ctx.fillStyle = "#fff"; // 设置底部背景色
      ctx.fillRect(0, size, size, realHeight - size); // 底部填充位置
      // 标题文字填充位置
      ctx.fillRect(
          fleft - textPadding / 2, 
          ftop - textPadding / 2,
          textWidth + textPadding,
          fontSize + textPadding
      );
      ctx.textBaseline = "top"; //设置绘制文本时的文本基线。
      ctx.fillStyle = "#333";// 文本颜色
      ctx.fillText(qrText, fleft, ftop); // 文本填充
    },
    // 下载二维码
    downloadQRCode() {
      let canvas = document.getElementById('QRCode_header')
      let a = document.createElement('a')
      a.href = canvas.toDataURL('img/png')
      a.download = '二维码cc'
      a.click()
    }
  },
  mounted() {
    this.getQRCode()
  },
};
</script>

vue-qr+html2canvas

<template>
  <div>
    <div id="qrcode-title">
      <vue-qr 
        id="qrcode-canvas" 
        :size="200" 
        :margin="10" 
        :text="'http://baidu.com'" 
        :logoSrc="require('../../assets/images/user-default.png')"
      ></vue-qr>
      <div>二维码标题</div>
    </div>
    <button @click="downloadQRCode">下载</button>
  </div>

</template>

<script>
import VueQr from 'vue-qr'
import html2canvas from 'html2canvas';
export default {
  components: {VueQr},
  methods: { 
    downloadQRCode() {
      html2canvas(document.getElementById('qrcode-title')).then(canvas => {
        let dataURL = canvas.toDataURL("image/png");
        if (dataURL !== "") {
          let a = document.createElement('a')
          a.download = "项目二维码";
          a.href = dataURL;
          a.click()
        }
      })
    }
  }
};
</script>

<style lang="scss" scoped>
#qrcode-title {
  width: 300px;
  display: flex;
  flex-direction: column;
}
#qrcode-title div {
  text-align: center;
  font-size: 20px;
  margin-top: 20px;
  margin-bottom: 20px;
}
</style>