# SnapDOM + jsPDF **Repository Path**: zhp26zhp/snap-dom---js-pdf ## Basic Information - **Project Name**: SnapDOM + jsPDF - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2025-12-26 - **Last Updated**: 2026-04-09 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Vue 3 进阶实战:使用 SnapDOM + jsPDF 生成高质量 PDF (含多页分页) 在Web开发中,将页面内容导出为PDF是一个非常常见的需求。过去,大家通常使用 `html2canvas` + `jsPDF` 的组合,但在面对复杂的CSS(如渐变、阴影)、Grid布局或大量DOM时,`html2canvas` 经常会出现样式丢失或渲染不准确的问题。 今天,我将向大家分享一个更现代、更高性能的替代方案——**SnapDOM**。它是一个专为高精度DOM捕捉而设计的引擎,配合 `jsPDF` 可以实现完美的PDF导出体验。 ## 🎯 方案对比:为什么不选 html2canvas? 在决定使用新技术之前,我们先看看主流方案的对比: | 特性 | html2canvas | SnapDOM | 备注 | | :--- | :--- | :--- | :--- | | **渲染原理** | 解析 DOM 并重建 Canvas | 深度克隆 DOM 并嵌入 SVG/Canvas | SnapDOM 更接近原生浏览器渲染 | | **CSS 支持** | 有限 (Flex/Grid/Filter 支持一般) | **优秀** (支持所有现代 CSS 特性) | SnapDOM 基本是“所见即所得” | | **伪元素** | 支持,但常见 bug | **完美支持** (::before, ::after) | | | **外部资源** | 需配置 CORS/Proxy | 内置更智能的资源内联机制 | 对图片/字体处理更友好 | | **性能** | 随 DOM 数量线性下降 | **极快** (基于原生 API 优化) | 大数据量下优势明显 | ## 🛠️ 第一步:环境准备 & 安装 首先,在你的 Vue 3 项目中安装必要的依赖: ```bash npm install @zumer/snapdom jspdf ``` ## 📝 第二步:编写“打印模版”组件 建议将需要导出的内容封装为一个独立的组件,这样更有利于样式的隔离和控制,确保导出的PDF布局整洁。由于 SnapDOM 是基于 DOM 截图,**所有的 CSS 都会被忠实记录**,所以推荐使用 scoped 样式。 **`src/components/InvoiceTemplate.vue`** ```vue DevStudio 专业数字化解决方案 账单明细 单号: {{ data.invoiceNumber }} 日期: {{ data.date }} 客户信息: {{ data.customerName }} 北京市海淀区中关村科技园 创新大厦 A 座 888 室 服务项目 数量 单价 金额 {{ item.desc }} {{ item.qty }} ¥{{ item.price.toFixed(2) }} ¥{{ (item.qty * item.price).toFixed(2) }} ``` ## ⚙️ 第三步:核心逻辑与分页实现 对于长内容(超过一页A4纸),如果不处理,PDF只会显示被截断的第一页。我们需要通过算法将生成的长图切割到多个PDF页面中。 **`src/App.vue`** ```vue Vue 3 + SnapDOM + jsPDF 演示 极速生成高质量 PDF (支持自动分页) {{ isLongContent ? '切换回单页内容' : '切换为长内容 (测试分页)' }} {{ isGenerating ? '正在生成...' : '导出 PDF' }} ``` ## 💡 深度解析:分页原理是怎样的? `jsPDF` 的 `addImage` 方法允许我们指定图片绘制的 `x, y` 坐标。 1. **Canvas 思维**:你可以把 PDF 页面想象成一个窗口,而生成长图是一张很长的海报。 2. **第一页**:我们将海报的顶部对齐窗口顶部(`y=0`)。 3. **第二页**:我们新建一个窗口,然后将海报**向上推**一个窗口的高度(`y = -PageHeight`)。 * 此时,海报的 `0 ~ PageHeight` 部分在窗口上方(不可见)。 * 海报的 `PageHeight ~ 2*PageHeight` 部分刚好在窗口内(可见)。 4. **循环**:以此类推,直到海报底部也滚出窗口。 **优缺点分析**: * ✅ **优点**:简单通用,无需修改 DOM 结构,样式 100% 还原。 * ⚠️ **缺点**:它是纯视觉切割,可能会把一行文字从中间切成两半(上半截在上一页,下半截在下一页)。 * **改进思路**:对于非常严格的报表,建议在生成图片前,预先计算每个 item 的高度,在 DOM 中插入强制分页符(`page-break-after`),但这通常需要配合浏览器原生打印(`window.print`),而在 `jsPDF` 纯前端生成方案中,上述“图片切分法”是性价比最高的方案。 ## ❓ 常见问题 (FAQ) **Q1: 导出的 PDF 图片模糊怎么办?** > **A**: 这是分辨率不足导致的。在调用 `snapdom.toPng(el, { scale: 2 })` 时,增加 `scale` 的值(如 2 或 3)。这相当于提高了 Canvas 的 DPI。注意:`scale` 过高会导致生成图片体积过大,可能会导致浏览器崩溃。 **Q2: 图片或字体没有显示出来?** > **A**: 这通常是跨域 (CORS) 问题。SnapDOM 会尝试内联图片,但如果图片服务器没有返回正确的 `Access-Control-Allow-Origin` 头,Canvas 会被污染或无法读取。确保你的 CDN 资源允许跨域,或者将图片转为 Base64 字符串再渲染。 **Q3: 如何不打印页面上的“导出”按钮?** > **A**: 有两种方法: > 1. 将打印内容(如 `InvoiceTemplate`)放在一个独立的、不可见的容器中(如 `position: absolute; left: -9999px`)。 > 2. 使用 `snapdom` 的选择器参数或临时隐藏 DOM 元素。在本 Demo 中,我们是直接传入了 `InvoiceTemplate` 的组件根元素,所以只要按钮不在这个组件里,自然就不会被打印。 ## 📦 总结与源码 使用 `SnapDOM` + `jsPDF` 你可以轻松实现: 1. **所见即所得**:完全还原Vue组件样式,支持圆角、阴影、渐变。 2. **高清输出**:自定义缩放倍数。 3. **自动分页**:通过简单的位移算法处理长表单。 希望这篇实战分享对你有帮助!如果你在项目中也需要生成精美的 PDF 报告,不妨试试这个组合。 **📂 获取完整源码:** [https://gitee.com/zhp26zhp/snap-dom---js-pdf](https://gitee.com/zhp26zhp/snap-dom---js-pdf)
专业数字化解决方案
单号: {{ data.invoiceNumber }}
日期: {{ data.date }}
{{ data.customerName }}
北京市海淀区中关村科技园
创新大厦 A 座 888 室
极速生成高质量 PDF (支持自动分页)