Vue项目中将界面转换为PDF并导出的实现方案
1. 主要技术栈
项目使用了以下库来实现PDF导出功能:
html2canvas
:将HTML元素转换为canvas图像jspdf
:生成PDF文件- 自定义的打印插件:基于
vue-print-nb
改进,支持水印等功能
npm install html2canvas jspdf
2. 核心实现方式
使用html2canvas + jspdf直接生成PDF
// 生成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);// 创建canvasconst 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();// 创建PDFconst imgData = canvas.toDataURL('image/png', 1.0);const pdf = new jsPDF('p', 'mm', 'a4');// 计算图片在PDF中的尺寸并添加到PDFconst 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. 使用示例
// 直接下载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);}
}