Vue3 二维码生成器实现方案(本项目实战拆解)
本文基于本项目的「二维码生成器」工具,拆解一套在 Vue3 / Nuxt3 项目中实现可视化二维码生成器的完整方案,重点放在页面结构与功能 JavaScript 的协作方式上,代码均来源于实际线上工具。
在线工具网址:https://see-tool.com/qr-code-generator
工具截图:
一、整体架构设计
本工具采用「Vue 负责结构和状态容器、独立 JS 负责绘制与交互」的分层思路:
- Vue 页面组件:
pages/qr-code-generator.vue,负责:- 渲染所有表单控件(文本/URL/邮箱/电话/SMS/WiFi/vCard 等类型)
- 输出带有
data-*标记的 DOM 结构,作为 JS 工具层的「挂载点」 - 提供预览区域、下载按钮区域,以及文档说明和相关工具组件
- 功能脚本一:
public/js/qr-code-generator-ui.js,只处理:- 类型卡片的选中态切换(
.qr-type-card) - 不同类型表单块的显隐(
.qr-input-form) - 监听
render-event/ 路由变化重新绑定
- 类型卡片的选中态切换(
- 功能脚本二:
public/js/qr-code-generator-tool.js,负责核心能力:- 动态加载第三方
qrcode-generator库 - 解析不同类型表单内容并组装成最终字符串
- 根据参数(尺寸、容错等级、前景色/背景色、点样式、定位角样式、中心 Logo)绘制二维码
- 生成 Canvas,并支持导出 PNG / SVG
- 监听输入变化,已生成过一次后自动「实时预览重绘」
- 动态加载第三方
这种拆分的好处是:Vue 只关心「结构和语义」,复杂的 Canvas 绘制逻辑完全放在独立 JS 中,通过data-qr-generator这一属性完成耦合。
二、Vue 页面:用>三、UI 交互层:类型切换与表单显隐
public/js/qr-code-generator-ui.js是一个自执行函数,仅做 UI 层交互:
setActiveType(root, type):- 遍历所有
.qr-type-card,给当前类型加上active,其它移除 - 遍历
.qr-input-form,data-form === type的移除hidden,其余加上hidden
- 遍历所有
bind(root):- 找到默认
active的卡片,或回退到text类型 - 给每张卡片绑定
click事件,切换类型
- 找到默认
init():- 通过
document.querySelectorAll('[data-qr-generator]')找到所有实例并绑定 - 监听
DOMContentLoaded、render-event、hashchange、popstate,确保在 SSR 渲染完成、前端路由切换后都能重新扫描并绑定
- 通过
这一层刻意不碰任何二维码算法或 Canvas,只负责「用户点哪里,看到哪个表单」。
四、核心工具层:从表单到二维码的完整流水线
public/js/qr-code-generator-tool.js是真正的核心,实现步骤可以拆成几块。
1. 环境准备与工具函数
loadScriptOnce(src):按 src 检查是否已经插入<script>,避免重复加载;如果脚本标签存在但库尚未就绪,则监听load/error。hexToRgba/isValidHexColor:处理颜色合法性与转换。normalizeUrl(url):为 URL 类型做 https 默认补全。getActiveType / getActiveDotStyle / getActiveEyeStyle:根据当前 DOM 选中态读出类型和样式。
2. 按类型组装内容字符串
getContentByType(root, type)是「业务协议」的核心,它根据类型从表单里取值,并组装不同的目标格式:
text:直接取纯文本;url:调用normalizeUrl,自动补https://;email:拼接为mailto:协议,支持 subject / body 参数;phone:tel:协议;sms:sms:号码?body=内容;wifi:按照标准 WiFi QR 协议拼出WIFI:T:WPA;S:SSID;P:PASSWORD;H:true;;;vcard:生成一个BEGIN:VCARD/END:VCARD的多行 vCard 文本,包含姓名、公司、电话、邮箱、网址等。
如果必填字段为空(如邮箱地址、WiFi SSID、vCard 姓名),函数会返回空字符串,后续生成逻辑会弹出「请填写必填字段」的通知而不是生成无效二维码。
3. Canvas 绘制:点阵 + 定位角 + Logo
生成二维码视觉效果的关键在buildQrCanvas:
- 通过第三方库
window.qrcode(0, errorLevel)生成二维码矩阵:addData(text)/make()得到qr.getModuleCount()和qr.isDark(row, col)。
- 创建 Canvas 并先用背景色铺底。
- 遍历矩阵:
- 通过
isInEyeFrame(row, col, moduleCount)判断当前 cell 是否属于三个位于角落的定位图形; - 非定位区域调用
drawDots(ctx, x, y, cellSize, dotStyle):square:纯方块;rounded:通过roundRect或手写 path 实现圆角矩形;dots:圆点样式。
- 通过
- 三个定位角通过
drawEyeFrame单独绘制,支持多种样式:- 通过 path / arc / 手写 roundRect 实现 diamond / leaf / dot / circle / extra-rounded / classy 等;
- 外框、内框、中心块用深浅色组合绘制。
- 如果用户上传了中心 Logo:
- 把图片读成 DataURL,
img.onload后在中心开一块浅底矩形,再绘制缩放后的 logo 图片。
- 把图片读成 DataURL,
最终返回一个 Promise,resolve 出完整绘制好的 Canvas。
4. 从 Canvas 导出 SVG
canvasToSvg(canvas, colorLight, colorDark)负责把渲染结果转成矢量 SVG:
- 读取整张 Canvas 的
imageData; - 先输出一个背景
rect,用浅色填充; - 再按像素遍历,凡是足够「黑」的像素,就在 path 中追加
M x,y h1 v1 h-1 z这种 1×1 小方块; - 最终得到一个单 path 的 SVG,方便下载和后续放大使用。
5. 绑定页面:生成、实时重绘与下载
bindQrTool(root)负责把整条流水线串起来:
- 先通过各种
data-field、.pattern-selector、.eye-frame-selector把 DOM 节点引用缓存下来; - 同步尺寸滑块与文字显示、同步颜色选择器与文本输入;
- 处理 Logo 上传、清除,以及文件名展示。
核心的生成逻辑在generate():
ensureLib():按需加载qrcode-generator.min.js,只加载一次;- 读取当前类型与内容,若为空则调用
window.showNotification提示并终止; - 读取尺寸、容错等级、颜色、点样式、定位角样式、Logo 等参数;
- 清空预览 DOM,调用
buildQrCanvas得到 Canvas; - 把 Canvas append 到预览容器中,并展示下载按钮;
- 记录
lastCanvas与hasGeneratedOnce标记,后续即可支持「改参数自动重绘」。
为了让体验更「所见即所得」,还提供了防抖重绘:
debounce(generate, 250)得到debouncedRegenerate;- 在尺寸滑块、容错等级选择、颜色输入、点样式/定位角样式、Logo 上传与清除、以及所有
.qr-input-form中的input/textarea/select/checkbox变动时触发; - 如果尚未生成过一次,则不会重绘,避免无意义计算。
最后是下载逻辑:
- PNG 下载:
lastCanvas.toDataURL('image/png')赋给临时<a>的href,设置download='qrcode.png'后触发点击; - SVG 下载:先用
canvasToSvg拿到字符串,再用 Blob +URL.createObjectURL生成临时链接,设置download='qrcode.svg'后点击并释放 URL。
五、在 Vue 项目中复用这套方案的要点
总结这套实现的关键点,其实就是一句话:Vue 负责结构和「可操作的标记」,具体的绘制逻辑用独立 JS 模块承载,通过>
STM32编码器正交解码:硬件模式与工程避坑指南
1. 增量型旋转编码器的工程本质与信号机理 增量型旋转编码器并非简单的“带方向的计数器”,而是一种基于正交信号相位关系实现无接触位置测量的机电传感器。其核心价值在于: 在不依赖绝对参考点的前提下,以极低成本实现高分辨率、双向、抗干…
Qwen3-Reranker-8B量化部署:在边缘设备上的实践
Qwen3-Reranker-8B量化部署:在边缘设备上的实践 最近在做一个工业质检的项目,客户需要在产线边缘设备上部署一个智能文档检索系统。需求很明确:要能快速从海量技术文档中找到相关段落,帮助现场工程师解决设备故障。但问题来了&am…
动漫转真人开源生态:AnythingtoRealCharacters2511社区贡献
动漫转真人开源生态:AnythingtoRealCharacters2511社区贡献 最近在玩动漫转真人,发现了一个挺有意思的现象。以前这类工具要么是闭源的商业软件,要么是个人开发者的小玩具,效果和稳定性都差强人意。但自从AnythingtoRealCharacte…
多模型对比测试:Whisper-large-v3在不同口音英语识别中的表现
多模型对比测试:Whisper-large-v3在不同口音英语识别中的表现 1. 为什么口音识别成了语音技术的真正试金石 你有没有遇到过这样的情况:会议录音里,印度同事的英语说得飞快,语调起伏像唱歌;澳洲客户在视频里把"a…
Qwen3-ForcedAligner-0.6B快速部署:视频剪辑字幕解决方案
Qwen3-ForcedAligner-0.6B快速部署:视频剪辑字幕解决方案 还在为视频剪辑时手动打轴、对齐字幕而烦恼吗?无论是制作短视频、整理会议录音,还是给卡拉OK视频配歌词,精准的时间轴对齐都是一项耗时费力的工作。传统方法要么依赖在线…
Qwen3-ASR-0.6B在智能家居场景的应用:语音控制中心实现
Qwen3-ASR-0.6B在智能家居场景的应用:语音控制中心实现 1. 当家里的灯开始听懂你说话时 上个月,我在朋友家第一次体验到那种“不用找遥控器”的生活。他站在客厅中央,只说了一句“把灯光调成暖黄,音量调小一点”,天花…