You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 20:51:25