在项目中,我们经常需要将一批二维码(比如库位、设备编号、物料标签等)批量导出成 PDF,方便打印或归档。
本文将介绍如何使用 jsPDF + qrcode 在前端实现这一功能,并支持 自动分页 和 布局控制(4×5 栅格)。
一、安装依赖
javascript
# 安装 jsPDF ------ 用于生成和导出 PDF 文件(浏览器端导出)
npm install jspdf
# 安装 qrcode ------ 用于在前端生成二维码(支持生成 Base64 图片)
npm install qrcode
# 安装 html2canvas ------ 用于将页面(DOM)渲染成图片,支持中文和样式
npm install html2canvas
二、引入模块
javascript
import QRCode from 'qrcode'
import jsPDF from 'jspdf'
import html2canvas from 'html2canvas'
三、核心实现思路
我们要实现的功能流程如下:
从后端接口获取要导出的数据。前端根据每条数据生成对应的二维码(Base64 图片)。将二维码和名称排版插入到 PDF。当一页二维码放满后,自动分页。导出并保存 PDF 文件。整个过程纯前端实现,无需后端参与,非常方便。
四、完整示例代码
javascript
//处理数据,将字段转成二维码
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()
}
},
// 生成二维码Base64
async generateQRCode(url) {
if (!url) return ''
try {
return await QRCode.toDataURL(url, {
errorCorrectionLevel: 'H',
width: 100,
margin: 1
})
} catch (e) {
console.error('二维码生成失败:', e)
return ''
}
},
//导出二维码 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 图片 Base64
const 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)
}
五、实现效果
