logo
GitHub

二维码生成工具实现

在本节中,我们将实现在线工具箱的二维码生成功能。主要包括以下功能点:

  • 文本/链接转二维码
  • 自定义二维码样式
    • 颜色选择
    • 大小调整
    • Logo 添加
  • 二维码下载(PNG/SVG)

页面设计

页面布局

pages/tools/qrcode.vue
<script setup lang="ts">
import { ref, computed } from 'vue'
// 表单数据
const form = ref({
content: '',
size: 200,
foreground: '#000000',
background: '#FFFFFF',
logo: null as File | null
})
// 二维码图片 URL
const qrcodeUrl = ref<string | null>(null)
// 生成二维码
async function handleGenerate() {
if (!form.value.content) {
return
}
const formData = new FormData()
formData.append('content', form.value.content)
formData.append('size', form.value.size.toString())
formData.append('foreground', form.value.foreground)
formData.append('background', form.value.background)
if (form.value.logo) {
formData.append('logo', form.value.logo)
}
try {
const response = await fetch('/api/qrcode/generate', {
method: 'POST',
body: formData
})
const data = await response.json()
if (!data.success) {
throw new Error(data.message)
}
qrcodeUrl.value = data.result.url
} catch (error) {
console.error('生成二维码失败:', error)
}
}
// 下载二维码
function handleDownload(format: 'png' | 'svg') {
if (!qrcodeUrl.value) return
const link = document.createElement('a')
link.href = qrcodeUrl.value
link.download = `qrcode.${format}`
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
}
// 处理 Logo 上传
function handleLogoUpload(event: Event) {
const input = event.target as HTMLInputElement
if (input.files && input.files[0]) {
form.value.logo = input.files[0]
}
}
</script>
<template>
<div class="container mx-auto px-4 py-8">
<h1 class="text-3xl font-bold mb-8">二维码生成</h1>
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
<!-- 左侧表单 -->
<div class="card bg-base-100 shadow-xl">
<div class="card-body">
<!-- 内容输入 -->
<div class="form-control">
<label class="label">
<span class="label-text">文本内容</span>
</label>
<textarea
v-model="form.content"
class="textarea textarea-bordered h-24"
placeholder="输入要转换的文本或链接"
/>
</div>
<!-- 大小设置 -->
<div class="form-control">
<label class="label">
<span class="label-text">二维码大小</span>
<span class="label-text-alt">{{ form.size }}px</span>
</label>
<input
v-model="form.size"
type="range"
min="100"
max="500"
class="range"
step="10"
/>
</div>
<!-- 颜色设置 -->
<div class="grid grid-cols-2 gap-4">
<div class="form-control">
<label class="label">
<span class="label-text">前景色</span>
</label>
<input
v-model="form.foreground"
type="color"
class="w-full h-10"
/>
</div>
<div class="form-control">
<label class="label">
<span class="label-text">背景色</span>
</label>
<input
v-model="form.background"
type="color"
class="w-full h-10"
/>
</div>
</div>
<!-- Logo 上传 -->
<div class="form-control">
<label class="label">
<span class="label-text">Logo 图片</span>
</label>
<input
type="file"
class="file-input file-input-bordered w-full"
accept="image/*"
@change="handleLogoUpload"
/>
</div>
<!-- 生成按钮 -->
<div class="mt-6">
<button
class="btn btn-primary w-full"
@click="handleGenerate"
:disabled="!form.content"
>
生成二维码
</button>
</div>
</div>
</div>
<!-- 右侧预览 -->
<div class="card bg-base-100 shadow-xl">
<div class="card-body">
<h2 class="card-title mb-4">预览</h2>
<div
v-if="qrcodeUrl"
class="flex flex-col items-center gap-4"
>
<img
:src="qrcodeUrl"
:alt="form.content"
class="max-w-full"
/>
<!-- 下载按钮 -->
<div class="flex gap-2">
<button
class="btn btn-outline"
@click="handleDownload('png')"
>
下载 PNG
</button>
<button
class="btn btn-outline"
@click="handleDownload('svg')"
>
下载 SVG
</button>
</div>
</div>
<div
v-else
class="flex items-center justify-center h-[300px] text-gray-400"
>
二维码预览区域
</div>
</div>
</div>
</div>
</div>
</template>

API 实现

server/api/qrcode/generate.ts
import { defineEventHandler } from 'h3'
import QRCode from 'qrcode'
import sharp from 'sharp'
export default defineEventHandler(async (event) => {
// 获取表单数据
const formData = await readMultipartFormData(event)
if (!formData) {
return {
success: false,
message: '请提供有效的表单数据'
}
}
// 解析参数
const content = formData.find(f => f.name === 'content')?.data.toString()
const size = parseInt(formData.find(f => f.name === 'size')?.data.toString() || '200')
const foreground = formData.find(f => f.name === 'foreground')?.data.toString() || '#000000'
const background = formData.find(f => f.name === 'background')?.data.toString() || '#FFFFFF'
const logo = formData.find(f => f.name === 'logo')?.data
if (!content) {
return {
success: false,
message: '请提供要转换的内容'
}
}
try {
// 生成二维码
const qrcode = await QRCode.toBuffer(content, {
errorCorrectionLevel: 'H',
margin: 1,
width: size,
color: {
dark: foreground,
light: background
}
})
// 如果有 Logo,添加到二维码中心
if (logo) {
const logoSize = Math.floor(size * 0.2) // Logo 大小为二维码的 20%
const logoBuffer = await sharp(logo)
.resize(logoSize, logoSize)
.toBuffer()
const qrcodeWithLogo = await sharp(qrcode)
.composite([
{
input: logoBuffer,
gravity: 'center'
}
])
.toBuffer()
return {
success: true,
result: {
url: `data:image/png;base64,${qrcodeWithLogo.toString('base64')}`
}
}
}
return {
success: true,
result: {
url: `data:image/png;base64,${qrcode.toString('base64')}`
}
}
} catch (error) {
console.error('生成二维码失败:', error)
return {
success: false,
message: '生成二维码失败,请重试'
}
}
})

使用说明

  1. 安装依赖
Terminal window
# 安装 QRCode 和图片处理库
npm install qrcode sharp
  1. 功能测试
  • 启动开发服务器:npm run dev
  • 访问 http://localhost:3000/tools/qrcode
  • 输入文本或链接
  • 自定义二维码样式
  • 生成并下载二维码

优化建议

  1. 性能优化

    • 添加生成结果缓存
    • 限制上传文件大小
    • 压缩生成的二维码图片
  2. 功能增强

    • 支持批量生成
    • 添加更多样式选项
    • 支持生成动态二维码
  3. 用户体验

    • 添加生成历史记录
    • 支持拖拽上传 Logo
    • 增加常用文本模板

下一步

完成二维码生成工具后,我们将继续开发:

  1. 图片处理功能
  2. 更多实用工具