@veaba/qrcode-js

纯 JavaScript 实现的 QRCode 生成库,无需 WASM,兼容性更好,适合对 WASM 有顾虑的场景。

安装

npm install @veaba/qrcode-js

与 WASM 版本的区别

特性 @veaba/qrcode-js @veaba/qrcode-wasm
依赖 需要加载 .wasm 文件
兼容性 IE11+ 现代浏览器
性能 更快
包大小 ~15KB ~45KB (含 wasm)
启动时间 即时 需要异步初始化
API 统一 统一

基础使用

创建 QRCode

import { QRCodeCore, QRErrorCorrectLevel } from '@veaba/qrcode-js';

// 创建 QRCode 实例(构造函数直接传入文本)
const qr = new QRCodeCore('https://github.com/veaba/qrcodes', QRErrorCorrectLevel.H);

// 获取 SVG
const svg = qr.toSVG(256);
document.getElementById('qrcode').innerHTML = svg;

指定尺寸

import { QRCodeCore, QRErrorCorrectLevel } from '@veaba/qrcode-js';

const qr = new QRCodeCore('https://github.com/veaba/qrcodes', QRErrorCorrectLevel.H);

// 生成 512x512 的 SVG
const svg = qr.toSVG(512);

使用缓存(推荐)

对于重复文本,使用缓存版本可大幅提升性能:

import { 
  generateRoundedQRCodeCached,
  clearQRCodeCache,
  getCacheStats
} from '@veaba/qrcode-js';

// 第一次生成会缓存
const svg1 = generateRoundedQRCodeCached('https://example.com', 256, 8);

// 第二次生成直接从缓存读取,速度提升 10 倍+
const svg2 = generateRoundedQRCodeCached('https://example.com', 256, 8);

// 查看缓存状态
console.log(getCacheStats()); // { size: 1, maxSize: 100, keys: [...] }

// 清空缓存
clearQRCodeCache();

样式化 QRCode

基础样式

import { QRCodeCore, QRErrorCorrectLevel } from '@veaba/qrcode-js';

const qr = new QRCodeCore('https://github.com/veaba/qrcodes', QRErrorCorrectLevel.H);

// 样式化 SVG
const styledSvg = qr.toStyledSVG({
  size: 256,
  colorDark: '#000000',
  colorLight: '#ffffff',
  borderRadius: 8,
  quietZone: 2,
});

渐变 QRCode

const gradientSvg = qr.toStyledSVG({
  size: 256,
  gradient: {
    color1: '#667eea',
    color2: '#764ba2',
  },
  quietZone: 2,
});

圆角 QRCode

const roundedSvg = qr.toStyledSVG({
  size: 256,
  borderRadius: 12, // 圆角半径
  quietZone: 2,
});

带 Logo 区域

const logoSvg = qr.toStyledSVG({
  size: 256,
  quietZone: 2,
  logoRegions: [
    { row: 8, col: 8, size: 5 }, // 中心 5x5 区域留白
  ],
});

预设样式函数

import {
  generateRoundedQRCode,
  generateGradientQRCode,
  generateQRCodeWithLogoArea,
  generateWechatStyleQRCode,
  generateDouyinStyleQRCode,
  generateAlipayStyleQRCode,
  generateXiaohongshuStyleQRCode,
  generateCyberpunkStyleQRCode,
  generateRetroStyleQRCode,
  generateMinimalStyleQRCode,
} from '@veaba/qrcode-js';

// 圆角
const svg1 = generateRoundedQRCode('https://github.com/veaba/qrcodes', 256, 8);

// 渐变
const svg2 = generateGradientQRCode('https://github.com/veaba/qrcodes', 256, '#667eea', '#764ba2');

// Logo 区域
const svg3 = generateQRCodeWithLogoArea('https://github.com/veaba/qrcodes', 256, 0.2);

// 微信风格
const svg4 = generateWechatStyleQRCode('https://weixin.qq.com', 256);

// 抖音风格
const svg5 = generateDouyinStyleQRCode('https://douyin.com', 256);

批量生成

import { generateBatchQRCodes, generateBatchQRCodesCached } from '@veaba/qrcode-js';

const texts = [
  'https://github.com/veaba/qrcodes/1',
  'https://github.com/veaba/qrcodes/2',
  'https://github.com/veaba/qrcodes/3',
];

// 批量生成
const svgs = generateBatchQRCodes(texts, { size: 256 });

// 缓存版本
const svgsCached = generateBatchQRCodesCached(texts, { size: 256 });

异步生成

import { generateQRCodeAsync, generateBatchAsync } from '@veaba/qrcode-js';

// 单个异步生成
const result = await generateQRCodeAsync('https://example.com', {
  size: 256,
  cache: true
});
console.log(result.svg);

// 批量异步生成
const results = await generateBatchAsync(texts, {
  size: 256,
  cache: true
});

获取模块数据

如果需要自定义渲染:

import { QRCodeCore, QRErrorCorrectLevel } from '@veaba/qrcode-js';

const qr = new QRCodeCore('https://github.com/veaba/qrcodes', QRErrorCorrectLevel.H);

// 获取模块数量
const count = qr.getModuleCount();
console.log(count); // 例如:25(Version 2)

// 检查某个位置是否为深色
for (let row = 0; row < count; row++) {
  for (let col = 0; col < count; col++) {
    if (qr.isDark(row, col)) {
      // 渲染深色模块
    }
  }
}

在框架中使用

React

import { QRCodeCore, QRErrorCorrectLevel } from '@veaba/qrcode-js';
import { useMemo } from 'react';

function QRCodeComponent({ text, size = 256 }) {
  const svg = useMemo(() => {
    const qr = new QRCodeCore(text, QRErrorCorrectLevel.H);
    return qr.toSVG(size);
  }, [text, size]);

  return <div dangerouslySetInnerHTML={{ __html: svg }} />;
}

Vue

<template>
  <div v-html="svg" />
</template>

<script setup>
  import { QRCodeCore, QRErrorCorrectLevel } from '@veaba/qrcode-js';
  import { computed } from 'vue';

  const props = defineProps({
    text: String,
    size: { type: Number, default: 256 },
  });

  const svg = computed(() => {
    const qr = new QRCodeCore(props.text, QRErrorCorrectLevel.H);
    return qr.toSVG(props.size);
  });
</script>

性能对比

与 WASM 版本的性能对比(ops/s):

测试项 @veaba/qrcode-js @veaba/qrcode-wasm
单条生成 (medium) 9,662 ~15,000
SVG 输出 9,827 ~17,000
缓存命中 ~500,000 ~500,000

虽然 WASM 更快,但纯 JS 版本在大多数场景下性能足够,且无需处理异步初始化的复杂性。

何时选择 @veaba/qrcode-js?

选择 @veaba/qrcode-js 而不是 @veaba/qrcode-wasm 的场景:

  • ✅ 需要支持 IE11 等旧浏览器
  • ✅ 对包大小敏感(JS 版本更小)
  • ✅ 不想处理 WASM 的异步初始化
  • ✅ 生成频率不高,性能不是瓶颈
  • ✅ 内容安全策略(CSP)限制 WASM

选择 @veaba/qrcode-wasm 的场景:

  • ✅ 追求极致性能
  • ✅ 高频批量生成
  • ✅ 现代浏览器环境

API 统一性

@veaba/qrcode-js@veaba/qrcode-wasm 提供完全一致的 API:

// 两个包的 API 完全相同
import { QRCodeCore, generateRoundedQRCodeCached } from '@veaba/qrcode-js';
// 或
import init, { QRCodeCore, generateRoundedQRCodeCached } from '@veaba/qrcode-wasm';
await init();

// 以下代码在两个包中完全相同
const qr = new QRCodeCore('text', QRErrorCorrectLevel.H);
const svg = qr.toSVG(256);
const styledSvg = generateRoundedQRCodeCached('text', 256, 8);

这使得在两个包之间切换变得非常容易,只需更改导入语句即可。