☰
qrcode+vue根据上传的文件和链接动态生成带水印的二维码
2026/9/27 9:08:07 网站建设 项目流程

废话不多说,直接上干活

<template v-if="activeName==1"> <el-form ref="qrForm" :model="qrForm" :rules="rules" label-width="80px" class="qr-form"> <!-- 链接输入框 --> <el-form-item label="目标链接" prop="url"> <el-input style="width: 80%;" type="textarea" :rows="5" v-model="qrForm.url" placeholder="请输入需要生成二维码的链接" clearable @input="handleUrlChange" ></el-input> </el-form-item> <!-- Logo上传区域 --> <el-form-item label="Logo图片"> <el-upload class="logo-uploader" action="" :auto-upload="false" :on-change="handleLogoChange" :show-file-list="false" accept="image/*" > <div> <el-button size="small" type="primary"> <i class="el-icon-upload"></i> 选择Logo </el-button> </div> </el-upload> <!-- Logo预览 --> <div v-if="logoPreview" class="logo-preview"> <el-image :src="logoPreview" style="width: 100px; height: 100px; margin-top: 10px" > <template #error> <div class="image-error">图片加载失败</div> </template> </el-image> <el-button size="mini" type="text" class="remove-logo" @click="removeLogo" > 移除 </el-button> </div> </el-form-item> <!-- 生成按钮 --> <el-form-item> <el-button type="primary" @click="generateQRCode" :loading="loading" > <span>生成二维码</span> </el-button> </el-form-item> </el-form> <!-- 二维码结果展示 --> <div v-if="qrCodeUrl" class="qr-result"> <el-divider content-position="left">生成结果</el-divider> <div class="qr-image-container"> <el-image :src="qrCodeUrl" :preview-src-list="[qrCodeUrl]" fit="contain" class="qr-image" > <template #error> <div class="image-error">二维码生成失败</div> </template> </el-image> </div> <el-button size="mini" type="text" class="download-btn" @click="downloadQRCode" > <el-icon><i class="el-icon-download"></i></el-icon> 下载二维码 </el-button> </div> </template> </el-card>

import QRCode from ‘qrcode’;
import { getName, getPhone } from “@/utils/auth”;
export default {
name: ‘QRCodeGenerator’,
data() {
return {
// 表单数据
qrForm: {
url: ‘’
},
// 表单验证规则
rules: {
url: [
{ required: true, message: ‘请输入链接’, trigger: ‘blur’ },
{ type: ‘url’, message: ‘请输入有效的URL’, trigger: ‘blur’ }
]
},
// 状态管理
logoFile: null, // 上传的Logo文件流
logoPreview: null, // Logo预览地址
qrCodeUrl: null, // 生成的二维码地址
loading: false , // 生成加载状态
activeName:‘1’
};
},
mounted(){
this.w a t e r m a r k . s e t ( ‘ watermark.set(`watermark.set(‘{getName()}KaTeX parse error: Expected 'EOF', got '}' at position 26: …)}`);// 添加水印 }̲, destroyed()…watermark.set(“”);
},
methods: {
// 处理链接变化
handleUrlChange() {
// 链接变化时可选择清除之前的二维码
this.qrCodeUrl = null;
},

// 处理Logo上传 handleLogoChange(file) { // 验证文件类型 if (!file.raw.type.startsWith('image/')) { this.$message.error('请上传图片格式的文件'); return; } // 验证文件大小(限制5MB以内) if (file.size > 5 * 1024 * 1024) { this.$message.error('Logo文件大小不能超过5MB'); return; } this.logoFile = file.raw; // 生成Logo预览 const reader = new FileReader(); reader.onload = (e) => { this.logoPreview = e.target.result; }; reader.readAsDataURL(file.raw); }, // 移除Logo removeLogo() { this.logoFile = null; this.logoPreview = null; this.qrCodeUrl = null; }, // 生成带Logo的二维码 async generateQRCode() { // 表单验证 this.$refs.qrForm.validate(async (valid) => { if (!valid) return; // if (!this.logoFile) { // this.$message.warning('请先上传Logo图片'); // return; // } this.loading = true; try { const qrSize = 300; // 二维码尺寸 const logoRatio = 0.2; // Logo占比(20%) // 1. 生成基础二维码 const qrBase64 = await QRCode.toDataURL(this.qrForm.url, { width: qrSize, margin: 1, color: { dark: '#333333', light: '#ffffff' } }); if(!this.logoFile){ this.qrCodeUrl = qrBase64; return false } // 2. 转换Logo文件流为Image对象 const logoImage = await this.fileToImage(this.logoFile); // 3. 合并二维码和Logo const qrWithLogo = await this.combineQrAndLogo( qrBase64, logoImage, qrSize, logoRatio ); this.qrCodeUrl = qrWithLogo; this.$message.success('二维码生成成功'); } catch (error) { console.error('生成二维码失败:', error); this.$message.error('二维码生成失败,请重试'); } finally { this.loading = false; } }); }, // 将文件流转为Image对象 fileToImage(file) { return new Promise((resolve, reject) => { const image = new Image(); const reader = new FileReader(); reader.onload = (e) => { image.onload = () => resolve(image); image.onerror = () => reject(new Error('Logo图片加载失败')); image.src = e.target.result; }; reader.onerror = () => reject(new Error('文件读取失败')); reader.readAsDataURL(file); }); }, // 合并二维码和Logo combineQrAndLogo(qrBase64, logoImage, qrSize, logoRatio) { return new Promise((resolve, reject) => { const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); canvas.width = qrSize; canvas.height = qrSize; // 绘制二维码 const qrImage = new Image(); qrImage.onload = () => { ctx.drawImage(qrImage, 0, 0, qrSize, qrSize); // 计算Logo尺寸和位置 const logoSize = qrSize * logoRatio; const x = (qrSize - logoSize) / 2; const y = (qrSize - logoSize) / 2; // 添加白色边框,增强识别度 ctx.fillStyle = '#ffffff'; ctx.fillRect(x - 3, y - 3, logoSize + 6, logoSize + 6); // 绘制Logo ctx.drawImage(logoImage, x, y, logoSize, logoSize); // 转为PNG格式返回 resolve(canvas.toDataURL('image/png')); }; qrImage.onerror = () => reject(new Error('二维码绘制失败')); qrImage.src = qrBase64; }); }, // 下载二维码 downloadQRCode() { if (!this.qrCodeUrl) return; const link = document.createElement('a'); link.download = 'qrcode.png'; link.href = this.qrCodeUrl; link.click(); }

}
};

::v-deep .el-card__header{
padding-bottom: 0 !important;
}
.toolBox{
padding: 30px 10px 10px 10px;
}
.qr-generator-card {
width: 100%;
/* margin: 20px auto; */
}

.header-icon {
margin-right: 8px;
color: #409EFF;
}

.header-title {
font-size: 16px;
font-weight: 500;
}

.qr-form {
margin-top: 15px;
}

.logo-uploader {
margin-top: 5px;
}

.logo-preview {
position: relative;
display: inline-block;
}

.remove-logo {
/* position: absolute;/
/
bottom: -20px;
left: 0; */
color: #F56C6C;
padding: 0;
}

.qr-result {
max-width: 300px;
margin-top: 20px;
display: flex;
justify-content: flex-start;
flex-direction: column;
margin-left: 34px;
}

.qr-image-container {
display: flex;
/* justify-content: center; */
padding: 20px;
}

.qr-image {
max-width: 300px;
max-height: 300px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
padding: 10px;
background: #fff;
}

.download-btn {
display: block;
color: #409EFF;
}

.image-error {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background: #f5f5f5;
color: #999;
}

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询