需求分析:界面展示的文字信息通过jsPDF、html2canvas渲染打印
html
<template>
<div style="padding: 16px; background: #fff">
<div>
<el-button type="primary" @click="downloadPDF">{{ '下载' }}</el-button>
<el-button type="primary" v-print="printConfig">{{ '打印' }}</el-button>
</div>
<div id="printContent" style="padding: 10px">
<h2 style="text-align: center">实验报告申请单</h2>
<el-divider>{{ '基本信息' }}</el-divider>
<el-descriptions :column="4" 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="'报告书名称'" :span="4">
<div style="white-space: pre-wrap">{{ form.reportName || '-' }}</div>
</el-descriptions-item>
<!-- 第三行 -->
<el-descriptions-item :label="'副标题'" :span="4">
<div style="white-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="'实验目的'" :span="4">
<div style="white-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="'其他附件'" :span="3">
<a v-if="form.fileName !== ''" style="margin-right: 2%; cursor: pointer" @click="handleClickLook">{{ form.fileName }}</a>
<span v-else> {{ '-' }}</span>
</el-descriptions-item>
</el-descriptions>
<el-divider>{{ '车辆信息' }}</el-divider>
<table class="print-table" border="1" cellpadding="8" cellspacing="0" width="100%">
<thead>
<tr style="background: #f5f7fa; text-align: left">
<th width="120">样车名称</th>
<th width="120">样车款型</th>
<th width="120">车牌号</th>
<th width="160">样车选装包信息</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, i) in tableConfig.tableDataList" :key="i" style="text-align: left">
<td>{{ item.vehicleModel || '-' }}</td>
<td>{{ item.vehicleConfig || '-' }}</td>
<td>{{ item.licensePlate || '-' }}</td>
<td>{{ item.optionPackInfo || '-' }}</td>
</tr>
<tr v-if="tableConfig.tableDataList.length === 0">
<td colspan="6" align="center">暂无数据</td>
</tr>
</tbody>
</table>
</div>
</div>
</template>
javascript
<script 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('打印窗口关闭')
}
}
</script>
css
<style>
/* 全局打印样式,确保表格永远对齐 */
@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
之前的写法: 转成了图片再进行下载
javascript
// 下载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`)
}