当前位置: 首页 > news >正文

二维码生成器:从前端到打印的全流程

二维码库的选择

前端生成二维码的库挺多的,我们用的是qrcode这个npm包,star数比较多,维护也比较活跃。

npm install qrcode

项目里的版本是1.5.4。

基本用法

二维码生成非常简单:

import QRCode from "qrcode"; QRCode.toDataURL("https://example.com").then(url => { console.log(url); // base64格式的图片数据 });

在我们的项目里,二维码生成是在支付场景下用的。用户选择充值套餐后,后端返回一个支付链接,前端把这个链接转成二维码显示:

<template> <el-dialog title="支付二维码" :visible.sync="openWeixinCode"> <div class="payPrice">¥ {{ rechargeList[activeRecharge].price }}</div> <el-image :src="orderInfo.url" fit="contain" class="wxCode"></el-image> <div class="payTip">请使用微信扫一扫,扫描二维码完成支付</div> </el-dialog> </template> <script> import QRCode from "qrcode"; export default { methods: { handlePay() { buyRechargePower(this.rechargeList[this.activeRecharge].id).then(res => { QRCode.toDataURL(res.data.url).then(url => { this.orderInfo.url = url; this.openWeixinCode = true; // 轮询支付状态 this.timer = setInterval(() => { this.getEnOrderStatus(); }, 2000); }); }); } } } </script>

第一个坑:二维码太复杂扫不出来

一开始生成的二维码特别复杂,感觉密密麻麻全是点,手机扫码很难识别。

后来查了一下文档,发现可以通过errorCorrectionLevel参数调整容错率:

QRCode.toDataURL(url, { errorCorrectionLevel: 'L' // L、M、Q、H,容错率从低到高 }).then(url => { // ... });

容错率越高,二维码越复杂但越抗污损。对于我们的场景(线上扫码显示在手机屏幕上),选L级别就够了,二维码会简洁很多,扫码速度快很多。

第二个坑:二维码尺寸和清晰度

默认生成的二维码分辨率不太高,在高清屏上有点模糊。可以设置width参数:

QRCode.toDataURL(url, { width: 300, // 宽度,单位是像素 margin: 2, // 边距,留白区域 color: { dark: '#000000', // 二维码颜色 light: '#FFFFFF' // 背景颜色 } }).then(url => { // ... });

这里有个坑:width设置太大,base64字符串会非常长,可能会超出浏览器localStorage的长度限制。一般300-400就够用了。

打印适配

名片是要打印的,所以二维码在打印时的效果很重要。

我们用的是html2canvas把整个名片转成图片,然后打印。这里有几个要注意的点:

1. 设置合适的DPI

打印用的图片分辨率要比屏幕显示的高。我们是在生成名片的时候,整体放大2倍:

import html2canvas from 'html2canvas'; html2canvas(element, { scale: 2, // 2倍分辨率 useCORS: true, // 支持跨域图片 backgroundColor: '#ffffff' }).then(canvas => { // canvas转图片... });

2. 二维码大小要合适

名片尺寸通常是90mm × 54mm,二维码占的比例不能太大,否则扫的时候距离要拉得很远;也不能太小,否则打印出来不清楚。

我们测试下来,二维码宽度在名片总宽度的30%-40%比较合适。比如名片宽度360px,二维码大概120-140px。

3. 考虑留白

二维码周围要留点白边,不然打印出来边缘被裁了可能就扫不出来了:

QRCode.toDataURL(url, { margin: 2, // 至少留2个模块的边距 // ... });

下载二维码图片

有时候用户想单独下载二维码图片,可以直接用base64转blob下载:

function downloadQRCode(text, filename) { QRCode.toDataURL(text).then(url => { const link = document.createElement('a'); link.href = url; link.download = filename || 'qrcode.png'; link.click(); }); }

或者配合file-saver库:

import { saveAs } from 'file-saver'; QRCode.toBlob(text).then(blob => { saveAs(blob, 'qrcode.png'); });

实时刷新支付状态

二维码生成后,要轮询后端接口看用户有没有支付成功:

handlePay() { buyRechargePower(this.rechargeList[this.activeRecharge].id).then(res => { this.orderInfo = res.data; QRCode.toDataURL(res.data.url).then(url => { this.orderInfo.url = url; this.openWeixinCode = true; // 每2秒查询一次支付状态 this.timer = setInterval(() => { this.getEnOrderStatus(); }, 2000); }); }); }, getEnOrderStatus() { getEnOrderStatus(this.orderInfo.orderId).then(res => { if (res.data.status == 1) { // 支付成功,清除定时器 if (this.timer) { clearInterval(this.timer); } this.$message.success("支付成功"); this.openWeixinCode = false; this.$emit("RechargeSuccess"); } }); }

这里要注意的是,组件销毁的时候一定要清除定时器:

beforeDestroy() { if (this.timer) { clearInterval(this.timer); } }

一些小技巧

1. 二维码加Logo

可以在生成的二维码中间加个小Logo,不过要注意:

  • Logo不能太大,一般占二维码面积的15%-20%
  • Logo颜色要和二维码有对比度
  • 最好用白色边框把Logo围起来

这个qrcode库本身不支持加Logo,得自己处理canvas。我们项目暂时没这个需求,就没做。

2. 批量生成

如果需要批量生成二维码,记得用Promise.all并行处理:

const urls = ['url1', 'url2', 'url3']; Promise.all(urls.map(url => QRCode.toDataURL(url))).then(results => { console.log(results); // 三张二维码的base64 });

3. 打印预览

打印前最好给用户一个预览功能,确认效果没问题再打印。浏览器有原生打印API:

window.print();

配合CSS的@media print可以控制打印时的样式:

@media print { .no-print { display: none; } .qrcode-container { page-break-inside: avoid; } }

总结

二维码功能虽然看起来简单,但真要做好细节还挺多的:

  1. 容错率要选对:根据使用场景调整,别一味追求高容错
  2. 尺寸要合适:屏幕显示和打印的尺寸要求不一样,要分别优化
  3. 打印效果要测试:别光看屏幕上的效果,打印出来看看实际效果
  4. 定时器要清理:轮询类的代码一定要在组件销毁时清除定时器
http://www.jsqmd.com/news/496832/

相关文章:

  • 霸王餐CPS系统中Java实现异步化处理提升系统吞吐量的技巧
  • 贪心算法集
  • MarioVerse:基于 Flutter × HarmonyOS 6.0 的超级玛丽游戏画布区域实现详解
  • Qwen2.5-VL-7B-Instruct图文交互教程:多模态思维链(MoT)提示工程
  • 算法基础·C++常用操作
  • 华为AI产品和技术由浅入深巅峰解析
  • SiameseUIE企业级落地案例:政务公文关键信息(人物/机构/事件)批量抽取
  • 常州代理记账哪家好?从一套“糊涂账”说起的实战拆解 - 企师傅推荐官
  • windows装系统教程
  • MarioVerse:基于 Flutter × HarmonyOS 6.0 的超级玛丽跨端游戏控制系统深度解析—从 UI 设计到跨端适配的「游戏控制区域」实战拆解
  • 2026年3月江苏铝合金工具箱/冷冻盒/走台板/托盘/高空作业平台/塔筒平台盖板生产厂家竞争格局深度分析报告 - 2026年企业推荐榜
  • 目前去渍最好的选哪款?2026真实测评美白去垢牙膏品牌推荐:洁净牙齿 - 资讯焦点
  • php python+vue请假考勤功能需求分析
  • AOP切面(是一种思想)
  • 如何在VirtualBox中安装银河麒麟桌面操作系统V10
  • UGUI不规则形状按钮(基于图标不透明区域)
  • Docker上部署前后端分离项目
  • 2026北京婚纱摄影机构对比:如何选到靠谱好店 - 博客万
  • 外贸企业为什么“有产品却没有客户”?问题可能出在获客方式 - 资讯焦点
  • C# WinForms机房管理系统源码|支持SQL Server/MySQL/Access多数据库|.NET Framework窗体应用
  • 机试搜索----dfs
  • OpenClaw企业级AI安全防护实战:七层策略+沙箱隔离+细粒度权限,彻底根治AI越权乱操作
  • C语言:字符函数和字符串函数—及模拟实现
  • 广柔扁平电缆在机器人AI技术创新应用中的前景探索 - 资讯焦点
  • PyQt:从图像文件或字节流生成QImage的速度测试
  • JMeter实战2--阶梯线程组及计算逻辑
  • 链接脚本优化(lsl或ld),Map文件解析,内存分析软件MapSee免费下载
  • ROS2的核心概念A-节点
  • Windows如何阻止应用程序联网
  • 灵芝孢子粉哪个牌子好?从破壁率、成分、口碑分析.