Skip to content

二维码生成与解析

本文档介绍如何使用现代前端技术实现二维码的生成与解析功能。

一、二维码生成

1.1 使用 qrcode.js 库

直接 URL 引入

html
<script src="qrcode.min.js"></script>

NPM 安装

bash
npm install qrcode
javascript
import QRCode from 'qrcode';

1.2 基本用法

javascript
// 创建二维码实例
const qrcode = new QRCode('qrcode-container', {
    text: 'https://www.example.com',
    width: 128,
    height: 128,
    colorDark: '#000000',
    colorLight: '#ffffff',
    correctLevel: QRCode.CorrectLevel.L
});

// 生成新的二维码
qrcode.makeCode('https://www.google.com');

// 清除二维码
qrcode.clear();

1.3 配置选项

选项类型默认值说明
textstring''二维码内容
widthnumber128二维码宽度
heightnumber128二维码高度
colorDarkstring'#000000'前景色
colorLightstring'#ffffff'背景色
correctLevelnumberQRCode.CorrectLevel.L纠错级别 (L, M, Q, H)

1.4 高级用法

生成 DataURL

javascript
// 获取生成的二维码 DataURL
const canvas = document.querySelector('#qrcode-container canvas');
const dataURL = canvas.toDataURL('image/png');
console.log('二维码 DataURL:', dataURL);

动态生成

javascript
// 输入框内容变化时重新生成二维码
const input = document.getElementById('input');
const btn = document.getElementById('generate-btn');

btn.addEventListener('click', () => {
    if (input.value.trim()) {
        qrcode.makeCode(input.value);
    }
});

二、二维码解析

2.1 使用 jsQR 库

直接 URL 引入

html
<script src="jsQR.min.js"></script>

NPM 安装

bash
npm install jsqr
javascript
import jsQR from 'jsqr';

2.2 从图片解析

从文件输入解析

javascript
const fileInput = document.getElementById('file-input');

fileInput.addEventListener('change', (e) => {
    const file = e.target.files[0];
    if (file) {
        const reader = new FileReader();
        reader.onload = function(e) {
            const img = new Image();
            img.onload = function() {
                const canvas = document.createElement('canvas');
                const ctx = canvas.getContext('2d');
                canvas.width = img.width;
                canvas.height = img.height;
                ctx.drawImage(img, 0, 0);
                
                const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
                const code = jsQR(imageData.data, canvas.width, canvas.height);
                
                if (code) {
                    console.log('解析结果:', code.data);
                } else {
                    console.log('未检测到二维码');
                }
            };
            img.src = e.target.result;
        };
        reader.readAsDataURL(file);
    }
});

从 URL 解析

javascript
async function parseQRCodeFromURL(url) {
    const img = new Image();
    img.crossOrigin = 'Anonymous';
    
    return new Promise((resolve, reject) => {
        img.onload = function() {
            const canvas = document.createElement('canvas');
            const ctx = canvas.getContext('2d');
            canvas.width = img.width;
            canvas.height = img.height;
            ctx.drawImage(img, 0, 0);
            
            const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
            const code = jsQR(imageData.data, canvas.width, canvas.height);
            
            if (code) {
                resolve(code.data);
            } else {
                reject(new Error('未检测到二维码'));
            }
        };
        
        img.onerror = function() {
            reject(new Error('图片加载失败'));
        };
        
        img.src = url;
    });
}

// 使用示例
parseQRCodeFromURL('https://example.com/qrcode.png')
    .then(result => console.log('解析结果:', result))
    .catch(error => console.error('解析失败:', error.message));

2.3 摄像头实时扫描

基本实现

javascript
async function startScanner() {
    if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
        throw new Error('浏览器不支持摄像头');
    }
    
    const stream = await navigator.mediaDevices.getUserMedia({ 
        video: { facingMode: 'environment' } 
    });
    
    const video = document.createElement('video');
    video.srcObject = stream;
    video.setAttribute('playsinline', true);
    video.play();
    
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    
    function scan() {
        if (video.readyState === video.HAVE_ENOUGH_DATA) {
            canvas.width = video.videoWidth;
            canvas.height = video.videoHeight;
            ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
            
            const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
            const code = jsQR(imageData.data, canvas.width, canvas.height);
            
            if (code) {
                console.log('扫描结果:', code.data);
                stream.getTracks().forEach(track => track.stop());
                return;
            }
        }
        requestAnimationFrame(scan);
    }
    
    requestAnimationFrame(scan);
    return stream;
}

// 使用示例
startScanner()
    .catch(error => console.error('启动扫描失败:', error.message));

三、综合应用

3.1 完整的二维码工具套件

我们提供了一个完整的二维码工具套件 QRCodeKit,集成了生成和解析功能:

javascript
// 生成二维码
const qr = QRCodeKit.create(document.getElementById('qrcode'), {
    width: 200,
    height: 200,
    text: 'https://www.example.com'
});

// 解析图片二维码
QRCodeKit.util.parseFromImage(fileInput.files[0])
    .then(result => console.log('解析结果:', result))
    .catch(error => console.error('解析失败:', error.message));

// 启动摄像头扫描
const scanner = QRCodeKit.scanner();
scanner.start(
    (data) => console.log('扫描结果:', data),
    document.getElementById('video-container')
);

3.2 示例项目

基本示例

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>二维码示例</title>
    <script src="qrcode.min.js"></script>
    <script src="jsQR.min.js"></script>
</head>
<body>
    <h1>二维码生成与解析示例</h1>
    
    <!-- 二维码生成 -->
    <div>
        <h2>1. 二维码生成</h2>
        <input type="text" id="input" placeholder="输入内容">
        <button id="generate-btn">生成二维码</button>
        <div id="qrcode" style="width: 200px; height: 200px; margin: 10px 0;"></div>
    </div>
    
    <!-- 二维码解析 -->
    <div>
        <h2>2. 二维码解析</h2>
        <input type="file" id="file-input" accept="image/*">
        <button id="parse-btn">解析图片</button>
        <div id="result"></div>
    </div>
    
    <script>
        // 初始化二维码生成器
        const qrcode = new QRCode('qrcode', {
            width: 200,
            height: 200
        });
        
        // 生成按钮点击事件
        document.getElementById('generate-btn').addEventListener('click', () => {
            const input = document.getElementById('input');
            if (input.value.trim()) {
                qrcode.makeCode(input.value);
            }
        });
        
        // 解析按钮点击事件
        document.getElementById('parse-btn').addEventListener('click', () => {
            const fileInput = document.getElementById('file-input');
            const resultDiv = document.getElementById('result');
            const file = fileInput.files[0];
            
            if (file) {
                const reader = new FileReader();
                reader.onload = function(e) {
                    const img = new Image();
                    img.onload = function() {
                        const canvas = document.createElement('canvas');
                        const ctx = canvas.getContext('2d');
                        canvas.width = img.width;
                        canvas.height = img.height;
                        ctx.drawImage(img, 0, 0);
                        
                        const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
                        const code = jsQR(imageData.data, canvas.width, canvas.height);
                        
                        if (code) {
                            resultDiv.textContent = `解析结果: ${code.data}`;
                            resultDiv.style.color = 'green';
                        } else {
                            resultDiv.textContent = '未检测到二维码';
                            resultDiv.style.color = 'red';
                        }
                    };
                    img.src = e.target.result;
                };
                reader.readAsDataURL(file);
            } else {
                resultDiv.textContent = '请选择图片文件';
                resultDiv.style.color = 'red';
            }
        });
    </script>
</body>
</html>

四、最佳实践

4.1 性能优化

  • 大图片处理:解析前对大图片进行缩放(建议最大1024px)
  • 扫描频率:摄像头扫描时设置合理的时间间隔(如300-500ms)
  • 资源管理:确保摄像头等资源正确释放
  • 错误处理:完善的错误捕获和用户提示

4.2 兼容性

  • 浏览器支持:现代浏览器都支持 Canvas API
  • HTTPS 要求:摄像头访问需要 HTTPS 环境
  • 设备支持:移动设备需要用户授权摄像头访问
  • 降级方案:提供手动输入选项作为备选

4.3 安全性

  • 内容验证:验证二维码内容的安全性
  • 输入过滤:对用户输入进行适当过滤
  • 权限管理:合理请求和使用摄像头权限
  • 数据处理:敏感信息加密处理

五、参考资源

六、常见问题

6.1 二维码生成失败

  • 问题:二维码不显示
  • 原因:可能是容器元素不存在或尺寸问题
  • 解决:确保容器元素存在且有足够的尺寸

6.2 摄像头访问失败

  • 问题:无法启动摄像头
  • 原因:可能是 HTTPS 环境问题或用户未授权
  • 解决:在 HTTPS 环境下测试,确保用户授权摄像头访问

6.3 二维码解析失败

  • 问题:无法解析二维码
  • 原因:可能是图片质量差或二维码不清晰
  • 解决:使用清晰的二维码图片,确保二维码完整可见

七、示例演示

我们提供了完整的示例代码,您可以直接查看和测试:

7.1 基础示例

7.2 示例文件结构

example/qrcode/
├── index.html         # 基础示例页面
├── test.html          # 完整测试页面
├── index.js           # 核心功能实现
├── qrcode.min.js      # 二维码生成库
├── jsQR.js            # 二维码解析库
└── qrcode-sample.png  # 示例二维码图片

7.3 如何使用示例

  1. 直接在浏览器中打开示例文件
  2. 在基础示例页面中测试二维码生成功能
  3. 在测试页面中测试完整的二维码生成、解析和摄像头扫描功能

通过本文档的介绍,您应该能够掌握二维码生成与解析的基本原理和实现方法。如需更详细的功能,可以参考相关库的官方文档。