vue2技术栈将表单内容转为PDF并下载
·
使用 html2canvas 和 jspdf 两个三方库实现。
html2canvas 是将表单内容以固定像素的方式截取变成图片
jspdf 是将图片转为 pdf
1. 下载两个库
npm install html2pdf.js
npm install jspdf.js
2. 创建一个 js 工具类
import html2canvas from 'html2canvas'
import jsPDF from 'jspdf'
import { Message } from 'element-ui'
/**
* 导出PDF(自动分页,不截断文字)
* @param {HTMLElement} element 要导出的DOM元素
* @param {string} filename 文件名,默认 '报告.pdf'
*/
export async function exportPDF(element, filename = '报告.pdf') {
if (!element) {
// console.error('导出失败:目标元素不存在')
Message.error('导出失败:目标元素不存在')
return
}
// 显示加载提示
const loadingTip = document.createElement('div')
loadingTip.textContent = '正在生成PDF,请稍候...'
loadingTip.style.cssText = `
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(0,0,0,0.7);
color: white;
padding: 12px 24px;
border-radius: 8px;
z-index: 9999;
font-size: 14px;
font-family: system-ui, -apple-system, sans-serif;
`
document.body.appendChild(loadingTip)
// 等待图片加载
const images = element.querySelectorAll('img')
await Promise.all(Array.from(images).map(img => {
if (img.complete) return Promise.resolve()
return new Promise((resolve) => {
img.onload = resolve
img.onerror = resolve
})
}))
await new Promise(resolve => setTimeout(resolve, 100))
// 获取尺寸
const contentWidth = element.scrollWidth
const contentHeight = element.scrollHeight
// 初始化PDF (A4竖版)
const pdf = new jsPDF('p', 'mm', 'a4')
const pageWidth = pdf.internal.pageSize.getWidth()
const pageHeight = pdf.internal.pageSize.getHeight()
const margin = 10
const pdfContentWidth = pageWidth - margin * 2
const pdfContentHeight = pageHeight - margin * 2
// 计算缩放比例
const pxToMm = 1 / 3.78
const scale = pdfContentWidth / (contentWidth * pxToMm)
const maxPageHeightPx = pdfContentHeight / pxToMm / scale
// 分页截图
let currentY = 0
let pageNum = 0
while (currentY < contentHeight) {
const captureHeight = Math.min(maxPageHeightPx, contentHeight - currentY)
if (captureHeight < 10) break
const canvas = await html2canvas(element, {
scale: 2,
useCORS: true,
backgroundColor: '#ffffff',
x: 0,
y: currentY,
width: contentWidth,
height: captureHeight,
scrollX: 0,
scrollY: 0,
onclone: (clonedDoc) => {
// 隐藏带 pdf-ignore 类的元素
clonedDoc.querySelectorAll('.pdf-ignore').forEach(el => {
el.style.display = 'none'
})
}
})
const imgData = canvas.toDataURL('image/jpeg', 0.9)
if (pageNum > 0) {
pdf.addPage()
}
const imgHeight = captureHeight * scale * pxToMm
pdf.addImage(imgData, 'JPEG', margin, margin, pdfContentWidth, imgHeight)
currentY += captureHeight
pageNum++
}
if (pageNum === 0) {
// console.error('导出失败:没有可导出的内容')
Message.error('导出失败:没有可导出的内容')
return
}
// 移除加载提示
if (loadingTip && loadingTip.parentNode) {
document.body.removeChild(loadingTip)
}
pdf.save(filename)
}
/**
* 打印表单(不改变原页面)
* @param {HTMLElement} element 要打印的DOM元素
* @param {string} title 打印标题
*/
export function printForm(element, title = '打印文档') {
if (!element) {
console.error('打印失败:目标元素不存在')
return
}
// 克隆要打印的内容(不影响原页面)
const printContent = element.cloneNode(true)
// 移除不需要打印的元素
printContent.querySelectorAll('.pdf-ignore, .no-print, button, .el-button').forEach(el => {
el.remove()
})
// 获取原页面所有样式
const styles = document.querySelectorAll('link[rel="stylesheet"], style')
let stylesHTML = ''
styles.forEach(style => {
if (style.tagName === 'LINK') {
stylesHTML += `<link href="${style.href}" rel="stylesheet">`
} else if (style.tagName === 'STYLE') {
stylesHTML += `<style>${style.innerHTML}</style>`
}
})
// 创建打印窗口
const printWindow = window.open('', '_blank')
printWindow.document.write(`
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>${title}</title>
${stylesHTML}
<style>
/* 重置body边距,保持原样 */
body {
margin: 0 !important;
padding: 20px !important;
background: white;
}
/* 打印时隐藏按钮类 */
@media print {
body {
padding: 0 !important;
}
.pdf-ignore, .no-print, button {
display: none !important;
}
}
</style>
</head>
<body>
${printContent.outerHTML}
</body>
</html>
`)
printWindow.document.close()
printWindow.onload = () => {
printWindow.print()
}
}
export default { exportPDF, printForm }
3. 使用该工具类
引入该工具类
import { printForm, exportPDF }from '@/utils/htmlToPdf' // 引入pdf工具类
定义一个按钮
<el-button type="primary" @click="exportPDF" size="small ">导出为PDF</el-button>
定义方法
使用一个div将需要转为pdf的区域全部包裹起来

async exportPDF() {
await exportPDF(this.$refs.formContainer, '测试报告')
},
更多推荐

所有评论(0)