需求分析界面展示的文字信息通过jsPDF、html2canvas渲染打印template div stylepadding: 16px; background: #fff div el-button typeprimary clickdownloadPDF{{ 下载 }}/el-button el-button typeprimary v-printprintConfig{{ 打印 }}/el-button /div div idprintContent stylepadding: 10px h2 styletext-align: center实验报告申请单/h2 el-divider{{ 基本信息 }}/el-divider el-descriptions :column4 border !-- 第一行 -- el-descriptions-item :label报告书编号{{ form.reportNo || - }}/el-descriptions-item el-descriptions-item :label发行人{{ form.issuerName || - }}/el-descriptions-item el-descriptions-item :label发行部门{{ form.issuerDept || - }}/el-descriptions-item el-descriptions-item :label发行日期{{ form.issueDate || - }}/el-descriptions-item !-- 第二行 -- el-descriptions-item :label报告书名称 :span4 div stylewhite-space: pre-wrap{{ form.reportName || - }}/div /el-descriptions-item !-- 第三行 -- el-descriptions-item :label副标题 :span4 div stylewhite-space: pre-wrap{{ form.subtitle || - }}/div /el-descriptions-item !-- 第四行 -- el-descriptions-item :label车型{{ form.carModel || - }}/el-descriptions-item el-descriptions-item :label阶段{{ form.phase || - }}/el-descriptions-item el-descriptions-item :label关联计划书{{ form.planNo || - }}/el-descriptions-item el-descriptions-item :label实验执行人{{ form.testExecutorName || - }}/el-descriptions-item !-- 第五行 -- el-descriptions-item :label抄送人{{ form.ccPersonName || - }}/el-descriptions-item el-descriptions-item :label实验类型{{ form.testType || - }}/el-descriptions-item el-descriptions-item :label实验开始时间{{ form.testStartTime || - }}/el-descriptions-item el-descriptions-item :label实验结束时间{{ form.testEndTime || - }}/el-descriptions-item !-- 第六和七行 -- el-descriptions-item :label实验目的 :span4 div stylewhite-space: pre-wrap; white-space: pre-line{{ form.testPurpose || - }}/div /el-descriptions-item !-- 第八行 -- el-descriptions-item :label实验结论{{ form.testConclusion || - }}/el-descriptions-item el-descriptions-item :label其他附件 :span3 a v-ifform.fileName ! stylemargin-right: 2%; cursor: pointer clickhandleClickLook{{ form.fileName }}/a span v-else {{ - }}/span /el-descriptions-item /el-descriptions el-divider{{ 车辆信息 }}/el-divider table classprint-table border1 cellpadding8 cellspacing0 width100% thead tr stylebackground: #f5f7fa; text-align: left th width120样车名称/th th width120样车款型/th th width120车牌号/th th width160样车选装包信息/th /tr /thead tbody tr v-for(item, i) in tableConfig.tableDataList :keyi styletext-align: left td{{ item.vehicleModel || - }}/td td{{ item.vehicleConfig || - }}/td td{{ item.licensePlate || - }}/td td{{ item.optionPackInfo || - }}/td /tr tr v-iftableConfig.tableDataList.length 0 td colspan6 aligncenter暂无数据/td /tr /tbody /table /div /div /templatescript setup import { reactive, onMounted, ref, watch } from vue import { flowReport } from workspace/api/parts/partStorage import { useRoute } from vue-router import { downFile } from workspace/api/driver.ts import { vPrint } from vue-print-next import html2canvas from html2canvas import jsPDF from jspdf const route useRoute() import { Editor, Toolbar } from wangeditor/editor-for-vue import moment from moment import { ElMessage } from element-plus // 优化下载PDF const downloadPDF () { const element document.getElementById(printContent) if (!element) return // 可选给个加载提示Element Plus ElMessage.success(PDF生成中请稍候...) // 关键优化配置 setTimeout(async () { const canvas await html2canvas(element, { scale: 1.5, // 从 2 → 1.5清晰度足够且快很多 logging: false, useCORS: true, // 解决图片跨域 allowTaint: false, removeContainer: true, // 自动清理DOM backgroundColor: #fff, // 强制白底避免透明渲染慢 onclone: (clonedDoc) { // 克隆文档里隐藏滚动条、去掉多余样式、加速渲染 const cloneEl clonedDoc.getElementById(printContent) if (cloneEl) { cloneEl.style.maxHeight none cloneEl.style.overflow visible } // 隐藏表格滚动条非常影响速度 const tables clonedDoc.querySelectorAll(.el-table) tables.forEach((t) { t.style.overflow visible t.style.maxHeight none }) } }) // A4 适配 const pdf new jsPDF(portrait, mm, a4) const imgWidth 210 const imgHeight (canvas.height * imgWidth) / canvas.width // 压缩图片核心提速 const imgData canvas.toDataURL(image/jpeg, 0.85) // 分页处理内容超长也不卡 let position 0 pdf.addImage(imgData, JPEG, 0, position, imgWidth, imgHeight) // 内容超过一页自动分页 while (imgHeight pdf.internal.pageSize.height) { position - pdf.internal.pageSize.height pdf.addPage() pdf.addImage(imgData, JPEG, 0, position, imgWidth, imgHeight) } pdf.save(${form.reportNo}${form.reportName}${moment().format(YYYY-MM-DD)}.pdf) ElMessage.success(PDF下载完成) }, 100) } // 打印 const printConfig { el: #printContent, // 需要打印的元素选择器 preview: true, // 开启打印预览推荐可以看到打印效果再决定是否打印 previewTitle: 打印预览, // 预览窗口标题 noPrintSelector: .no-print, // 忽略指定选择器的元素不打印 paperSize: A4, // 纸张尺寸可选 A4, Letter, Legal 等 orientation: portrait, // 纸张方向: portrait 纵向, landscape 横向 popTitle: 实验报告详情, // 打印页面的页眉标题 extraCss: https://example.com/print.css, // 额外引入的打印样式表 openCallback() { console.log(打印窗口已打开) }, closeCallback() { console.log(打印窗口关闭) } } /scriptstyle /* 全局打印样式确保表格永远对齐 */ media print { .print-table { width: 100% !important; table-layout: fixed !important; border-collapse: collapse !important; } .print-table th, .print-table td { word-break: break-all !important; white-space: normal !important; } } /style style scoped /* 页面展示样式 */ .print-table { width: 100%; border-collapse: collapse; margin: 10px 0; } .print-table th, .print-table td { word-break: break-all; } /style这样打印的pdf文件只有一百多kb之前打印的文件是十几M之前的写法: 转成了图片再进行下载// 下载PDF const downloadPDF async () { const element document.getElementById(printContent) const canvas await html2canvas(element, { scale: 2, logging: false, useCORS: true }) const pdf new jsPDF({ orientation: portrait, unit: mm, format: a4 }) const imgData canvas.toDataURL(image/png) const imgWidth 210 const imgHeight (canvas.height * imgWidth) / canvas.width pdf.addImage(imgData, PNG, 0, 0, imgWidth, imgHeight) pdf.save(${实验计划}_${moment().format(YYYYMMDD)}.pdf) }
前端PDF下载、打印界面
发布时间:2026/6/7 16:25:30
需求分析界面展示的文字信息通过jsPDF、html2canvas渲染打印template div stylepadding: 16px; background: #fff div el-button typeprimary clickdownloadPDF{{ 下载 }}/el-button el-button typeprimary v-printprintConfig{{ 打印 }}/el-button /div div idprintContent stylepadding: 10px h2 styletext-align: center实验报告申请单/h2 el-divider{{ 基本信息 }}/el-divider el-descriptions :column4 border !-- 第一行 -- el-descriptions-item :label报告书编号{{ form.reportNo || - }}/el-descriptions-item el-descriptions-item :label发行人{{ form.issuerName || - }}/el-descriptions-item el-descriptions-item :label发行部门{{ form.issuerDept || - }}/el-descriptions-item el-descriptions-item :label发行日期{{ form.issueDate || - }}/el-descriptions-item !-- 第二行 -- el-descriptions-item :label报告书名称 :span4 div stylewhite-space: pre-wrap{{ form.reportName || - }}/div /el-descriptions-item !-- 第三行 -- el-descriptions-item :label副标题 :span4 div stylewhite-space: pre-wrap{{ form.subtitle || - }}/div /el-descriptions-item !-- 第四行 -- el-descriptions-item :label车型{{ form.carModel || - }}/el-descriptions-item el-descriptions-item :label阶段{{ form.phase || - }}/el-descriptions-item el-descriptions-item :label关联计划书{{ form.planNo || - }}/el-descriptions-item el-descriptions-item :label实验执行人{{ form.testExecutorName || - }}/el-descriptions-item !-- 第五行 -- el-descriptions-item :label抄送人{{ form.ccPersonName || - }}/el-descriptions-item el-descriptions-item :label实验类型{{ form.testType || - }}/el-descriptions-item el-descriptions-item :label实验开始时间{{ form.testStartTime || - }}/el-descriptions-item el-descriptions-item :label实验结束时间{{ form.testEndTime || - }}/el-descriptions-item !-- 第六和七行 -- el-descriptions-item :label实验目的 :span4 div stylewhite-space: pre-wrap; white-space: pre-line{{ form.testPurpose || - }}/div /el-descriptions-item !-- 第八行 -- el-descriptions-item :label实验结论{{ form.testConclusion || - }}/el-descriptions-item el-descriptions-item :label其他附件 :span3 a v-ifform.fileName ! stylemargin-right: 2%; cursor: pointer clickhandleClickLook{{ form.fileName }}/a span v-else {{ - }}/span /el-descriptions-item /el-descriptions el-divider{{ 车辆信息 }}/el-divider table classprint-table border1 cellpadding8 cellspacing0 width100% thead tr stylebackground: #f5f7fa; text-align: left th width120样车名称/th th width120样车款型/th th width120车牌号/th th width160样车选装包信息/th /tr /thead tbody tr v-for(item, i) in tableConfig.tableDataList :keyi styletext-align: left td{{ item.vehicleModel || - }}/td td{{ item.vehicleConfig || - }}/td td{{ item.licensePlate || - }}/td td{{ item.optionPackInfo || - }}/td /tr tr v-iftableConfig.tableDataList.length 0 td colspan6 aligncenter暂无数据/td /tr /tbody /table /div /div /templatescript setup import { reactive, onMounted, ref, watch } from vue import { flowReport } from workspace/api/parts/partStorage import { useRoute } from vue-router import { downFile } from workspace/api/driver.ts import { vPrint } from vue-print-next import html2canvas from html2canvas import jsPDF from jspdf const route useRoute() import { Editor, Toolbar } from wangeditor/editor-for-vue import moment from moment import { ElMessage } from element-plus // 优化下载PDF const downloadPDF () { const element document.getElementById(printContent) if (!element) return // 可选给个加载提示Element Plus ElMessage.success(PDF生成中请稍候...) // 关键优化配置 setTimeout(async () { const canvas await html2canvas(element, { scale: 1.5, // 从 2 → 1.5清晰度足够且快很多 logging: false, useCORS: true, // 解决图片跨域 allowTaint: false, removeContainer: true, // 自动清理DOM backgroundColor: #fff, // 强制白底避免透明渲染慢 onclone: (clonedDoc) { // 克隆文档里隐藏滚动条、去掉多余样式、加速渲染 const cloneEl clonedDoc.getElementById(printContent) if (cloneEl) { cloneEl.style.maxHeight none cloneEl.style.overflow visible } // 隐藏表格滚动条非常影响速度 const tables clonedDoc.querySelectorAll(.el-table) tables.forEach((t) { t.style.overflow visible t.style.maxHeight none }) } }) // A4 适配 const pdf new jsPDF(portrait, mm, a4) const imgWidth 210 const imgHeight (canvas.height * imgWidth) / canvas.width // 压缩图片核心提速 const imgData canvas.toDataURL(image/jpeg, 0.85) // 分页处理内容超长也不卡 let position 0 pdf.addImage(imgData, JPEG, 0, position, imgWidth, imgHeight) // 内容超过一页自动分页 while (imgHeight pdf.internal.pageSize.height) { position - pdf.internal.pageSize.height pdf.addPage() pdf.addImage(imgData, JPEG, 0, position, imgWidth, imgHeight) } pdf.save(${form.reportNo}${form.reportName}${moment().format(YYYY-MM-DD)}.pdf) ElMessage.success(PDF下载完成) }, 100) } // 打印 const printConfig { el: #printContent, // 需要打印的元素选择器 preview: true, // 开启打印预览推荐可以看到打印效果再决定是否打印 previewTitle: 打印预览, // 预览窗口标题 noPrintSelector: .no-print, // 忽略指定选择器的元素不打印 paperSize: A4, // 纸张尺寸可选 A4, Letter, Legal 等 orientation: portrait, // 纸张方向: portrait 纵向, landscape 横向 popTitle: 实验报告详情, // 打印页面的页眉标题 extraCss: https://example.com/print.css, // 额外引入的打印样式表 openCallback() { console.log(打印窗口已打开) }, closeCallback() { console.log(打印窗口关闭) } } /scriptstyle /* 全局打印样式确保表格永远对齐 */ media print { .print-table { width: 100% !important; table-layout: fixed !important; border-collapse: collapse !important; } .print-table th, .print-table td { word-break: break-all !important; white-space: normal !important; } } /style style scoped /* 页面展示样式 */ .print-table { width: 100%; border-collapse: collapse; margin: 10px 0; } .print-table th, .print-table td { word-break: break-all; } /style这样打印的pdf文件只有一百多kb之前打印的文件是十几M之前的写法: 转成了图片再进行下载// 下载PDF const downloadPDF async () { const element document.getElementById(printContent) const canvas await html2canvas(element, { scale: 2, logging: false, useCORS: true }) const pdf new jsPDF({ orientation: portrait, unit: mm, format: a4 }) const imgData canvas.toDataURL(image/png) const imgWidth 210 const imgHeight (canvas.height * imgWidth) / canvas.width pdf.addImage(imgData, PNG, 0, 0, imgWidth, imgHeight) pdf.save(${实验计划}_${moment().format(YYYYMMDD)}.pdf) }