最近写了一个 二维码生成与解析的网页应用,本文记录过程。
目录:
使用 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>
)
}
↶ 返回首页 ↶