如何使用Next.js将指定div导出为支持自定义尺寸的格式化PDF
Next.js 实现指定Div导出为多尺寸横向PDF方案
适配CLP标签导出场景,支持A5-A8横向规格选择,兼容Next.js全版本与Tailwind CSS样式。
1. 安装依赖
选用html2canvas做DOM转画布、jsPDF做PDF生成,两个库均为纯客户端实现,无服务端兼容问题:
npm install html2canvas jspdf
2. 预置纸张规格
提前定义A5-A8横向的标准尺寸(单位:mm,和jsPDF默认单位对齐):
- A5横向:宽210mm × 高148mm
- A6横向:宽148mm × 高105mm
- A7横向:宽105mm × 高74mm
- A8横向:宽74mm × 高52mm
3. 核心实现代码
注意:App Router 模式下必须在组件顶部加
'use client'指令,避免服务端渲染时找不到浏览器API报错;Pages Router 可直接使用。
'use client' import { useRef, useState } from 'react' import html2canvas from 'html2canvas' import jsPDF from 'jspdf' // 纸张尺寸配置 const PAPER_SIZES = { A5: { width: 210, height: 148 }, A6: { width: 148, height: 105 }, A7: { width: 105, height: 74 }, A8: { width: 74, height: 52 } } as const type PaperSizeKey = keyof typeof PAPER_SIZES export default function ClpLabelExport() { // 绑定要导出的标签容器 const labelRef = useRef<HTMLDivElement>(null) const [selectedSize, setSelectedSize] = useState<PaperSizeKey>('A5') const [exporting, setExporting] = useState(false) // 导出逻辑 const handleExportPdf = async () => { if (!labelRef.current) return setExporting(true) try { // DOM转高清画布 const canvas = await html2canvas(labelRef.current, { scale: 2, // 数值越高导出越清晰,文件体积也越大,2足够日常打印使用 useCORS: true, // 支持跨域图片渲染 logging: false }) const imgData = canvas.toDataURL('image/png') const { width: pdfW, height: pdfH } = PAPER_SIZES[selectedSize] // 初始化横向PDF const pdf = new jsPDF({ orientation: 'landscape', unit: 'mm', format: [pdfW, pdfH] }) // 图片撑满整页,无留白 pdf.addImage(imgData, 'PNG', 0, 0, pdfW, pdfH) // 导出文件 pdf.save(`CLP标签_${selectedSize}横向_${Date.now()}.pdf`) } catch (err) { console.error('PDF导出失败:', err) } finally { setExporting(false) } } return ( <div className="p-6 max-w-4xl mx-auto"> {/* 导出控制栏 */} <div className="flex gap-4 items-center mb-6"> <label className="text-sm font-medium">标签尺寸:</label> <select value={selectedSize} onChange={(e) => setSelectedSize(e.target.value as PaperSizeKey)} className="border rounded px-3 py-1.5 text-sm" > {Object.keys(PAPER_SIZES).map(size => ( <option key={size} value={size}>{size} 横向</option> ))} </select> <button onClick={handleExportPdf} disabled={exporting} className="bg-blue-600 hover:bg-blue-700 text-white px-4 py-1.5 rounded text-sm disabled:bg-gray-400" > {exporting ? '导出中...' : '导出PDF'} </button> </div> {/* CLP标签容器,宽高比和选中纸张保持一致,预览即所得 */} <div ref={labelRef} className="border bg-white p-6 shadow-sm" style={{ aspectRatio: `${PAPER_SIZES[selectedSize].width} / ${PAPER_SIZES[selectedSize].height}`, width: '100%' }} > {/* 此区域放表单自动排版生成的CLP标签内容 */} <h3 className="text-xl font-bold mb-4">CLP危险化学品标签</h3> <p>用户表单填写的内容会自动在此区域完成排版</p> </div> </div> ) }
4. 常见问题注意事项
- 样式丢失问题:Tailwind写的样式只要页面加载完成后是正常生效的,html2canvas就能正常识别渲染,不要用
::before/::after伪元素承载核心文本、图标内容,这类伪元素渲染兼容性差容易丢内容。 - 导出模糊问题:调整html2canvas的
scale参数到2-3即可,不要设置过高,否则生成的PDF体积会过大。 - 图片加载失败:如果标签内有外部图片资源,需要图片存储服务器配置跨域允许,同时保持
useCORS: true参数开启。 - 内容变形问题:标签容器通过
aspectRatio绑定和选中纸张完全一致的宽高比,就能保证预览效果和导出PDF效果完全一致,不会出现拉伸、多余留白问题。
内容的提问来源于stack exchange,提问作者Pokzy
相关产品推荐
相关产品推荐

