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

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

二维码库的选择

前端生成二维码的库挺多的,我们用的是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>¥ {{ rechargeList[activeRecharge].price }}</div> <el-image :src="orderInfo.url" fit="contain"></el-image> <div>请使用微信扫一扫,扫描二维码完成支付</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. 定时器要清理:轮询类的代码一定要在组件销毁时清除定时器

Read more

前端文件上传方案:别再只用input type=file了

前端文件上传方案:别再只用input type=file了

前端文件上传方案:别再只用input type=file了 毒舌时刻 这代码写得跟网红滤镜似的——仅供参考。 各位前端同行,咱们今天聊聊前端文件上传。别告诉我你还在用原生的input上传大文件,那感觉就像在用小水管灌满游泳池——慢得让人绝望。 为什么你需要文件上传方案 最近看到一个项目,上传100MB的文件直接卡死浏览器,没有任何进度提示,我差点当场去世。我就想问:你是在做上传还是在做浏览器杀手? 反面教材 <!-- 反面教材:原生文件上传 --> <input type="file" onchange="uploadFile(this.files[0])" /> <script> function uploadFile(file) { const formData = new FormData(

noteDigger:终极前端扒谱工具,让音乐制作变得简单快速

noteDigger:终极前端扒谱工具,让音乐制作变得简单快速 【免费下载链接】noteDigger在线前端频率分析扒谱 front-end music transcription 项目地址: https://gitcode.com/gh_mirrors/no/noteDigger noteDigger是一款创新的前端扒谱工具,专为音乐创作者和制作人设计。这款免费工具采用纯前端技术,无需安装任何软件或依赖库,双击即可使用,让音乐扒谱变得前所未有的简单!🎵 为什么选择noteDigger进行音乐扒谱? 在数字音乐时代,扒谱工具是每位音乐制作人的必备利器。noteDigger以其独特的优势脱颖而出: * 零配置使用:直接打开HTML文件即可开始工作 * 现代UI设计:直观的界面让新手也能快速上手 * 自主技术栈:完全自主研发,不依赖任何框架,项目体积小巧 * 跨平台兼容:支持所有现代浏览器,包括Chrome、Firefox等 快速上手:三步完成音乐扒谱 第一步:导入音频文件 noteDigger支持多种音频格式,包括常见的MP3、WAV文件,甚至视频格式如MP

前端实战:基于Vue3与免费满血版DeepSeek实现无限滚动+懒加载+瀑布流模块及优化策略

前端实战:基于Vue3与免费满血版DeepSeek实现无限滚动+懒加载+瀑布流模块及优化策略

目录 前端实战:基于Vue3与免费满血版DeepSeek实现无限滚动+懒加载+瀑布流模块及优化策略 一、前言 二、如何使用腾讯云免费满血版deepseek 1、腾讯云大模型知识引擎体验中心 2、体验deepseek联网助手 3、人机交互获取AI支持 三、基于DeepSeek实现无限滚动+懒加载+瀑布流模块 1、无限滚动+懒加载+瀑布流模块的底层逻辑 2、人机交互策略与Deepseek的实现过程 ①虚拟列表管理 ②布局容器初始化 ③动态渲染与销毁机制 ④无线滚动实现 ⑤内存优化策略 四、最终代码呈现 1、组件代码 2、组件用法 五、结语         作者:watermelo37         ZEEKLOG万粉博主、华为云云享专家、阿里云专家博主、腾讯云、支付宝合作作者,全平台博客昵称watermelo37。         一个假装是giser的coder,做不只专注于业务逻辑的前端工程师,Java、Docker、

从 “一脸懵” 到 Web 题 “稳拿分”:CTF Web 方向入门到进阶全攻略

从 “一脸懵” 到 Web 题 “稳拿分”:CTF Web 方向入门到进阶全攻略

从 “一脸懵” 到 Web 题 “稳拿分”:CTF Web 方向入门到进阶全攻略 刚接触 CTF 时,很多人都会被 Web 方向 “劝退”—— 打开题目看到一堆代码、抓包改参数、蹦出 “SQL 注入”“XSS” 等黑话,瞬间大脑空白:“这到底在考啥?” 但其实 CTF Web 是入门门槛最低、得分最稳的方向之一 —— 只要掌握核心漏洞原理,配合工具和思路,从 “一题不会” 到 “中等题稳拿”,3 个月就能实现突破。这篇文章从新手视角出发,带你拆解 Web 题的套路,梳理学习路径,帮你快速入门 CTF Web! 一、先搞懂:CTF Web