封装好用的页面导出 PDF 工具 Hook (html2canvas + jspdf)
在最近的一个项目中,遇到将页面内容(详情页)导出为 PDF 的需求。目前似乎没有直接将 DOM 转为 PDF 的一步到位技术,因此封装了一个间接转换的方法。基于 Vue3 + TypeScript 的通用 Hook 封装,利用 html2canvas 和 jspdf 实现网页内容导出为 PDF,并解决了滚动截断、清晰度不足以及自动分页等常见问题。
一、技术选型
- html2canvas: 将 DOM 元素转换为 Canvas 图片。
- jspdf: 将 Canvas 图片生成 PDF 文件。
- 封装: 使用 Hook 方式封装,方便复用。
二、核心痛点与解决方案
在实现过程中,通常会遇到以下几个问题:
- 导出内容不全: 如果页面有滚动条,直接截图只能截取可视区域。
- 解法: 在截图前将 DOM 高度设置为 auto,并获取 scrollHeight 传递给 html2canvas 的 windowHeight 参数。
- 图片模糊: 默认截图出来的 PDF 很模糊。
- 解法: 设置 scale: 2,提高 Canvas 的像素密度。
- PDF 分页问题: 长图直接放入 PDF 会被压缩变形。
- 解法: 计算内容高度与 A4 纸高度的比例,通过循环 addPage() 实现自动分页切割。
三、源码实现
新建文件 useExportPdf.ts,下载依赖 html2canvas 和 jspdf 然后引入:
import html2canvas from 'html2canvas';
import jsPDF from 'jspdf';
/**
* 导出页面为 PDF
* @param dom 需要导出的 DOM 元素
* @param fileName 导出的文件名(不含后缀)
*/
export const useExportPDF = async (dom: HTMLElement, fileName: string) => {
const element = dom;
if (!element) {
console.error('导出失败,未找到导出元素');
return;
}
// 1. 解决滚动截断问题:获取元素实际高度
originalHeight = element.;
originalStyleHeight = element..;
element.. = ;
{
canvas = (element, {
: ,
: ,
: -.,
: ,
: originalHeight,
});
pdf = (, , );
imgWidth = ;
imgHeight = (canvas. * imgWidth) / canvas.;
pdfPageHeight = pdf...();
position = ;
pdf.(canvas, , , - position, imgWidth, imgHeight);
position += pdfPageHeight;
(position < imgHeight) {
pdf.();
pdf.(canvas, , , - position, imgWidth, imgHeight);
position += pdfPageHeight;
}
pdf.();
} (error) {
.(, error);
} {
element.. = originalStyleHeight;
}
};


