1. 主要技术栈
项目使用了以下库来实现PDF导出功能:
html2canvas
:将HTML元素转换为canvas图像jspdf
:生成PDF文件- 自定义的打印插件:基于
vue-print-nb
改进,支持水印等功能
javascript
npm install html2canvas jspdf
2. 核心实现方式
使用html2canvas + jspdf直接生成PDF
javascript
// 生成PDF的核心方法
async generatePDF() {
try {
// 获取要导出的DOM元素
const element = this.$refs.pdfContent;
// 临时隐藏不需要打印的元素
const noPrintElements = element.querySelectorAll('.no-print');
const originalDisplays = [];
noPrintElements.forEach((el, index) => {
originalDisplays[index] = el.style.display;
el.style.display = 'none';
});
// 临时添加PDF导出专用样式
const style = document.createElement('style');
style.id = 'pdf-export-style';
style.textContent = `
.duty-table {
width: 1200px !important;
max-width: none !important;
font-size: 14px !important;
// ... 更多样式
}
`;
document.head.appendChild(style);
// 创建canvas
const canvas = await html2canvas(element, {
scale: 2, // 清晰度
useCORS: true,
allowTaint: true,
backgroundColor: '#ffffff',
width: 1200,
height: element.scrollHeight,
ignoreElements: (el) => {
return el.classList.contains('no-print');
}
});
// 恢复隐藏的元素和样式
noPrintElements.forEach((el, index) => {
el.style.display = originalDisplays[index];
});
document.getElementById('pdf-export-style')?.remove();
// 创建PDF
const imgData = canvas.toDataURL('image/png', 1.0);
const pdf = new jsPDF('p', 'mm', 'a4');
// 计算图片在PDF中的尺寸并添加到PDF
const a4Width = 210;
const a4Height = 297;
const margin = 5;
// ... 尺寸计算逻辑
pdf.addImage(imgData, 'PNG', xOffset, yOffset, imgWidth, imgHeight);
// 转换为Blob对象
const pdfBlob = pdf.output('blob');
const fileName = `排班表_${this.currentDate}_${new Date().getTime()}.pdf`;
return {
fileName: fileName,
pdfBlob: pdfBlob,
message: "PDF生成成功"
};
} catch (error) {
console.error('PDF导出错误:', error);
return null;
}
}
3. 实现要点总结
样式处理
- 为不需要打印的元素添加no-print类
- 临时添加专为PDF导出优化的CSS样式
- 处理字体和颜色(打印时通常需要将背景色设为白色)
导出流程
- 获取需要导出的DOM元素
- 使用html2canvas将其渲染为canvas
- 使用jspdf将canvas图像转换为PDF
- 通过Blob对象处理PDF数据,提供下载或上传功能
特殊处理
- 水印添加:通过CSS或在canvas上叠加实现
- 分页处理:计算内容高度,必要时分页
- 样式隔离:临时添加导出专用样式,处理完成后恢复
4. 使用示例
javascript
// 直接下载PDF
async exportPDF() {
const result = await this.generatePDF();
if (result) {
const url = URL.createObjectURL(result.pdfBlob);
const link = document.createElement('a');
link.href = url;
link.download = result.fileName;
link.click();
URL.revokeObjectURL(url);
}
}
// 上传PDF到服务器
async exportAndUpload() {
const result = await this.generatePDF();
if (result && result.pdfBlob) {
const formData = new FormData();
const pdfFile = new File([result.pdfBlob], result.fileName, {
type: "application/pdf",
});
formData.append("pdfFile", pdfFile);
// 发送请求上传文件
await uploadPDF(formData);
}
}