reactjs 实现二维码生成和解析功能

2025-11-17 16:10:36

最近写了一个 二维码生成与解析的网页应用,本文记录过程。

目录:

一、生成二维码

使用 qrcode 生成二维码,输入是字符串,输出是 base64 图片字符串,可以在 img 标签中设置 src 属性显示二维码。

下载二维码原理是创建 a 标签,设置 href 和 download 属性,通过 js 点击 a 标签进行下载,最后移除 a 标签。

import { useState } from 'react'
import QRCode from 'qrcode'

export default function GeneraoeQRCode() {
    const [ text, setText ] = useState('')
    const [ qrCodeUrl, setQrCodeUrl ] = useState('')

    const onGenerateQRCode = async () => {
        if (!text.trim()) return
        
        try {
            const url = await QRCode.toDataURL(text, {
                width: 400,
                margin: 2,
                color: {
                    dark: "#000000",
                    light: "#FFFFFF",
                },
            })
            setQrCodeUrl(url)
        } catch (error) {
            console.error("Error generating QR code:", error)
        }
    }

    const onDownloadQRCode = () => {
        if (!qrCodeUrl) return
        const link = document.createElement('a')
        link.href = qrCodeUrl
        link.download = 'qrcode.png'
        document.body.appendChild(link)
        link.click()
        document.body.removeChild(link)
    }

    return (
        <div>
            <input 
                type="text" 
                placeholder="输入文本" 
                value={text}
                onChange={e => setText(e.target.value)}
            />
            <button onClick={onGenerateQRCode}>
                生成二维码
            </button>
            <button onClick={onDownloadQRCode}>
                下载二维码
            </button>
            <div>
                <img
                  src={qrCodeUrl}
                  alt="Generated QR Code"
                />
            </div>
        </div>
    )
}

二、解析二维码:上传图片进行解析

使用 jsqr 解析二维码,输入是 imageData,输出是解析后的文本字符串。

获取 imageData 思路:

  • input type="file" 可以上传图片,获取 File 对象;
  • URL.createObjectURL(file) 将 File 对象转换为本地访问链接;
  • img.src = url 创建 img 标签,src 属性设置为图片本地链接;
  • img.onload 图片加载完成后,获取 canvas 画布;
  • ctx.drawImage(img, 0, 0) 将图片绘制到画布中;
  • ctx.getImageData(0, 0, canvas.width, canvas.height) 获取 canvas 画布中的图片数据;
  • jsQR(imageData.data, imageData.width, imageData.height) 解析二维码,获取解析后的文本字符串;
import { useRef, useState } from 'react'
import jsQR from 'jsqr'

export default function ParseQRCode() {
    const [ text, setText ] = useState('')
    const [qrCodeUrl, setQrCodeUrl] = useState('')
    const canvasRef = useRef<HTMLCanvasElement>(null)

    const onFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        const file = e.target.files?.[0]
        if (file) {
            onProcessImage(file) 
        }
    }

    const onProcessImage = async (file: File) => {
        try {
            const url = URL.createObjectURL(file)
            setQrCodeUrl(url)

            const img = new Image()
            img.src = url

            img.onload = () => {
                const canvas = canvasRef.current
                if (!canvas) return

                const ctx = canvas.getContext('2d')
                if (!ctx) return

                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, imageData.width, imageData.height)

                if (code) {
                    setText(code.data)
                }
            }
        } catch (err) {
            console.error("Error processing image:", err)
        }
    }

    return (
        <div>
            <input 
                type="file" 
                accept="image/*" 
                onChange={onFileChange}
            />
            <img 
                src={qrCodeUrl} 
                alt="QR Code" 
            />
            <input 
                type="text" 
                value={text}
            />
            <canvas 
                ref={canvasRef} 
                style={{ display: 'none' }} 
            />
        </div>
    )
}

三、解析二维码:复制粘贴图片进行解析

有时希望可以复制二维码,粘贴图片直接进行解析。

原理就是监听 paste 粘贴事件,使用 getAsFile() API 获取 File 文件,之后的思路和第二步的 解析二维码:上传图片进行解析 一样。

import { useEffect, useRef, useState } from 'react'
import jsQR from 'jsqr'

export default function ParseQRCode() {
    const [text, setText] = useState('')
    const [qrCodeUrl, setQrCodeUrl] = useState('')
    const canvasRef = useRef<HTMLCanvasElement>(null)

    useEffect(() => {
        // Listen for paste events
        const handlePaste = (e: ClipboardEvent) => {
            const items = e.clipboardData?.items
            if (!items) return

            for (let i = 0; i < items.length; i++) {
                if (items[i].type.indexOf('image') !== -1) {
                    const file = items[i].getAsFile()
                    if (file) {
                        e.preventDefault()
                        onProcessImage(file)
                    }
                }
            }
        }

        document.addEventListener('paste', handlePaste)
        return () => document.removeEventListener('paste', handlePaste)
    }, [])

    const onProcessImage = async (file: File) => {
        try {
            const url = URL.createObjectURL(file)
            setQrCodeUrl(url)

            const img = new Image()
            img.src = url

            img.onload = () => {
                const canvas = canvasRef.current
                if (!canvas) return

                const ctx = canvas.getContext('2d')
                if (!ctx) return

                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, imageData.width, imageData.height)

                if (code) {
                    setText(code.data)
                }
            }
        } catch (err) {
            console.error("Error processing image:", err)
        }
    }

    return (
        <div>
            <div>粘贴图片</div>
            <img
                src={qrCodeUrl}
                alt="QR Code"
            />
            <input
                type="text"
                value={text}
            />
            <canvas
                ref={canvasRef}
                style={{ display: 'none' }}
            />
        </div>
    )
}

返回首页

本文总阅读量  次
皖ICP备17026209号-3
总访问量: 
总访客量: