uniapp生成二维码(uQRCode)与自定义绘制样式与内容

二维码生成使用了一款基于Javascript环境开发的插件 uQRCode ,它不仅适用于uniapp,也适用于所有Javascript运行环境的前端应用和Node.js。

uQRCode 插件地址:https://ext.dcloud.net.cn/plugin?id=1287

目录

1、npm安装

2、通过import引入

3、生成二维码

4、自定义绘制样式与内容


1、npm安装

bash 复制代码
npm install uqrcodejs
# 或者
npm install @uqrcode/js

2、通过import引入

bash 复制代码
import UQRCode from 'uqrcodejs'; // npm install uqrcodejs
// 或者
import UQRCode from '@uqrcode/js'; // npm install @uqrcode/js

3、生成二维码

如果只是生成二维码的话实现也特别简单,在template中加入canvas组件,并在script中创建UQRCode对象配置参数调用绘制方法即可。

html 复制代码
<canvas id="qrcode" canvas-id="qrcode" style="width: 300px;height:300px;" />
TypeScript 复制代码
const qr = new UQRCode();
qr.data = '二维码内容';
qr.size = 300;
qr.make();
const ctx = uni.createCanvasContext('qrcode', this); // 组件内调用需传this,vue3 中 this 为 getCurrentInstance()?.proxy
qr.canvasContext = ctx;
qr.drawCanvas();

当然,除绘制简单的黑白块二维码外,UQRCode还支持定制块颜色、背景颜色、块形状、块之间的间距等,可绘制出各种花里胡哨的二维码,具体用法可查阅官方文档,本文不做阐述,

4、自定义绘制样式与内容

原本是可以先通过UQRCode插件把二维码生成并保存为图片,再绘制到新的画布上,但考虑到绘制时长和性能问题,我还是更想直接在二维码的画布上进行绘制。

4.1 定义配置信息

TypeScript 复制代码
const config = {
  qrcodeTitle: '二维码标题',
  logo: '二维码中间logo链接',
  qrcodeTitlePosition: 'center',
  borderWidth: 10,
};

  /** 是否为标题logo */
  const isTitleLogo = config.qrcodeTitle && config.logo && config.qrcodeTitlePosition === 'center';
  /** 是否有标题 */
  const hasTitle = config.qrcodeTitle && ['top', 'bottom'].includes(config.qrcodeTitlePosition);

其中borderWidth为边框宽度,qrcodeTitlePosition为二维码标题位置

|-------------------------|----------|------------------------------------------------------------|
| qrcodeTitlePosition 枚举值 | 效果 | 条件 |
| center | 标题在二维码中间 | 当logo为空且qrcodeTitle有值时,会将qrcodeTitle的内容生成为白底黑字的图片绘制在二维码中间。 |
| top | 标题在二维码上方 | 当qrcodeTitle有值时,会将qrcodeTitle的内容绘制在二维码上方。 |
| bottom | 标题在二维码上方 | 当qrcodeTitle有值时,会将qrcodeTitle的内容绘制在二维码下方。 |

4.2 初始配置:指定二维码内容和大小,将areaColor=''由自己绘制二维码背景,且在qr.make()之前设置margin留出绘制边框的空间,预留空间包含边框宽度(borderWidth)和边框与二维码的间距(示例为10)

html 复制代码
const qr = new UQRCode();
qr.data = '二维码内容';
qr.size = 300;
qr.areaColor = ''; // 不绘制背景,否则会覆盖边框或文本
qr.drawReserve = true; // 保留绘制,本次绘制是否接着上一次绘制。是二维码绘制完是否还能上此基础上绘制的关键
if (config.borderWidth > 0)
  qr.margin = config.borderWidth + 10;
qr.make();

4.3 绘制logo:如果二维码中间需要绘制logo,UQRCode是支持设置logo的,无需自己绘制。

TypeScript 复制代码
if (config.logo)
  qr.foregroundImageSrc = config.logo; // 网络图片需先下载下来

4.4 绘制二维码背景:如果二维码上下方有标题则需要高度需要留出空间来绘制(示例用 hasTitleDraw 来判断上下方是否有标题需绘制)

TypeScript 复制代码
const ctx = uni.createCanvasContext('qrcode', this); // 组件内调用需传this,vue3 中 this 为 getCurrentInstance()?.proxy
const hasTitleDraw = !isTitleLogo && hasTitle;
ctx.setFillStyle('#fff');
ctx.rect(0, 0, 300, hasTitleDraw ? 356 : 300);
ctx.fill();

4.5 计算字符占用长度:用来计算每行绘制的文字个数

TypeScript 复制代码
function textLength(str: string, index?: number) {
  let m = 0;
  const a = str.split('');
  for (let i = 0; i < a.length; i++) {
    if (a[i].charCodeAt(0) < 299)
      m++;
    else
      m += 2;
    if (index) {
      if (m == index)
        return i;
      else if (m > index)
        return i - 1;
      else if (i == a.length - 1)
        return a.length;
    }
  }
  return m;
}

4.6 绘制标题

TypeScript 复制代码
const isTop = config.qrcodeTitlePosition === 'top';
const title = config.qrcodeTitle;
if (hasTitleDraw) {
  ctx.setFontSize(30);
  ctx.setFillStyle('#000');
  ctx.setTextBaseline('top');
  ctx.fillText(
    title,
    Math.max(300 - textLength(title) * 16) / 2, 0),
    isTop ? 16 : 316,
  );
  if (isTop) { // 标题在二维码上方,整个二维码向下偏移
    qr.getDrawModules().forEach((item) => {
      item.y += 56;
    });
  }
}

4.7 绘制边框

TypeScript 复制代码
const hasTopTitle = hasTitle && isTop;
if (qr.margin > 0) {
  ctx.beginPath();
  ctx.setFillStyle('#000');
  // 左侧border
  ctx.rect(0, hasTopTitle ? 58 : 0, config.borderWidth, 300);
  // 右侧border
  ctx.rect(300 - config.borderWidth, hasTopTitle ? 58 : 0, config.borderWidth, 300);
  // 上方border
  ctx.rect(0, hasTopTitle ? 58 : 0, 300, config.borderWidth);
  // 下方border
  ctx.rect(0, 300 - config.borderWidth + (hasTopTitle ? 58 : 0), 300, config.borderWidth);
  ctx.fill();
}

4.8 绘制二维码中间的标题logo

TypeScript 复制代码
qr.canvasContext = ctx;
qr.drawCanvas(false)
  .then(async () => {
    // 绘制标题图片logo
    if (isTitleLogo) {
      // 绘制logo背景
      ctx.beginPath();
      ctx.setFillStyle('#fff');
      const x = 300 * 3 / 4 / 2;
      const y = x + (hasTopTitle ? 56 : 0);
      ctx.rect(x, y, 76, 76);
      ctx.fill();
      // 绘制logo文字
      ctx.setFontSize(30);
      ctx.setFillStyle('#000');
      ctx.setTextBaseline('top');
      // 绘制第1行文字
      let s = textLength(title) > 4 ? y + 14 : y + 28;
      let i = textLength(title, 4);
      const t1 = title.slice(0, i + 1);
      ctx.fillText(t1, x + (76 - textLength(t1) * 16) / 2, s);
      let t2 = title.slice(i + 1);
      // 绘制第2行文字
      if (t2.length > 0) {
        s += 68;
        i = textLength(t2, 4);
        t2 = t2.slice(0, i + 1);
        ctx.fillText(t2, x + (76 - textLength(t2) * 16) / 2, s);
      }
      ctx.draw(true, async () => {
        // 绘制完成,这里可以进行保存图片操作,如果还是太快可以setTimeout
      });
    }
    else {
      // 绘制完成,这里可以进行保存图片操作,如果还是太快可以setTimeout
    }
  });
相关推荐
逐·風3 小时前
unity关于自定义渲染、内存管理、性能调优、复杂物理模拟、并行计算以及插件开发
前端·unity·c#
Devil枫3 小时前
Vue 3 单元测试与E2E测试
前端·vue.js·单元测试
Yaml44 小时前
Spring Boot 与 Vue 共筑二手书籍交易卓越平台
java·spring boot·后端·mysql·spring·vue·二手书籍
尚梦4 小时前
uni-app 封装刘海状态栏(适用小程序, h5, 头条小程序)
前端·小程序·uni-app
GIS程序媛—椰子4 小时前
【Vue 全家桶】6、vue-router 路由(更新中)
前端·vue.js
前端青山5 小时前
Node.js-增强 API 安全性和性能优化
开发语言·前端·javascript·性能优化·前端框架·node.js
毕业设计制作和分享5 小时前
ssm《数据库系统原理》课程平台的设计与实现+vue
前端·数据库·vue.js·oracle·mybatis
清灵xmf7 小时前
在 Vue 中实现与优化轮询技术
前端·javascript·vue·轮询
大佩梨7 小时前
VUE+Vite之环境文件配置及使用环境变量
前端
GDAL7 小时前
npm入门教程1:npm简介
前端·npm·node.js