vue实现批量导出二维码到PDF(支持分页生成 PDF)
在项目中,我们经常需要将一批二维码(比如库位、设备编号、物料标签等)批量导出成 PDF,方便打印或归档。
本文将介绍如何使用 jsPDF + qrcode 在前端实现这一功能,并支持 自动分页 和 布局控制(4×5 栅格)。
一、安装依赖
# 安装 jsPDF —— 用于生成和导出 PDF 文件(浏览器端导出)
npm install jspdf# 安装 qrcode —— 用于在前端生成二维码(支持生成 Base64 图片)
npm install qrcode# 安装 html2canvas —— 用于将页面(DOM)渲染成图片,支持中文和样式
npm install html2canvas
二、引入模块
import QRCode from 'qrcode'
import jsPDF from 'jspdf'
import html2canvas from 'html2canvas'
三、核心实现思路
我们要实现的功能流程如下:
从后端接口获取要导出的数据。前端根据每条数据生成对应的二维码(Base64 图片)。将二维码和名称排版插入到 PDF。当一页二维码放满后,自动分页。导出并保存 PDF 文件。整个过程纯前端实现,无需后端参与,非常方便。
四、完整示例代码
// 生成二维码Base64async generateQRCode(url) {if (!url) return ''try {return await QRCode.toDataURL(url, {errorCorrectionLevel: 'H',width: 100,margin: 1})} catch (e) {console.error('二维码生成失败:', e)return ''}},//导出所有库位二维码async exportLocation() {try {this.$modal.loading('正在生成二维码,请稍候...')const rows = [{ name: 'A区-01号货位', number: 'LOC-001' },{ name: 'A区-02号货位', number: 'LOC-002' },{ name: 'A区-03号货位', number: 'LOC-003' },{ name: 'B区-01号货位', number: 'LOC-004' },{ name: 'B区-02号货位', number: 'LOC-005' },{ name: 'B区-03号货位', number: 'LOC-006' },{ name: 'C区-01号货位', number: 'LOC-007' },{ name: 'C区-02号货位', number: 'LOC-008' },{ name: 'C区-03号货位', number: 'LOC-009' },{ name: 'D区-01号货位', number: 'LOC-010' }]// 并行生成二维码const qrList = await Promise.all(rows.map(async (item) => {const qrCodeUrl = await this.generateQRCode(number)return {name: item.name || '',snCode: qrCodeUrl}}))await this.exportPdf(qrList)this.$modal.msgSuccess(`导出成功,共 ${qrList.length} 条数据`)} catch (err) {this.$modal.msgError('导出失败,请稍后重试')console.error(err)} finally {this.$modal.closeLoading()}},//导出二维码 PDF(4×5 布局自动分页,支持中文显示,无需字体文件)async exportPdf(qrList) {// 创建一个临时的 DOM 容器,用于渲染要导出的内容const container = document.createElement('div')container.style.width = '210mm' // 设置宽度为 A4 页面宽度container.style.padding = '10mm' // 设置页面边距container.style.display = 'grid' // 使用网格布局,方便排列container.style.gridTemplateColumns = 'repeat(4, 1fr)' // 每行 4 列container.style.gridGap = '10px' // 每个二维码块之间的间距container.style.textAlign = 'center' // 文本居中// 将每个二维码数据添加到容器中qrList.forEach(item => {const div = document.createElement('div') // 每个二维码块div.style.display = 'flex'div.style.flexDirection = 'column'div.style.alignItems = 'center'// 创建二维码图片const img = document.createElement('img')img.src = item.snCode // 二维码 Base64 图片img.style.width = '35mm' // 设置二维码大小img.style.height = '35mm'// 创建二维码下方的中文名称const text = document.createElement('div')text.textContent = item.name // ✅ 支持中文text.style.fontSize = '12px'text.style.marginTop = '4px' // 图片与文字之间的间距// 组合到单个块中div.appendChild(img)div.appendChild(text)container.appendChild(div)})// 将生成的容器暂时添加到页面(否则 html2canvas 无法渲染)document.body.appendChild(container)// 使用 html2canvas 将 DOM 转为图片const canvas = await html2canvas(container, {scale: 2, // 提高清晰度(2倍分辨率)useCORS: true // 允许跨域加载图片(二维码)})// 将 canvas 转成 PNG 图片 Base64const imgData = canvas.toDataURL('image/png')// 创建 PDF 对象const pdf = new jsPDF('p', 'mm', 'a4') // 纵向(p),单位毫米(mm),A4 尺寸const imgWidth = 210 // A4 宽度(mm)const pageHeight = 295 // A4 高度(mm)const imgHeight = (canvas.height * imgWidth) / canvas.width // 按比例计算图片高度// 将图片插入到 PDF 中pdf.addImage(imgData, 'PNG', 0, 0, imgWidth, imgHeight)// 保存 PDF 文件pdf.save('二维码导出.pdf')// 清理临时 DOM(不影响页面)document.body.removeChild(container)
}