vue3将页面导出成PDF文件(完美解决图片、表格内容分割问题)
1、安装依赖
npm install --save html2canvas
npm install jspdf --save
2、在utils中创建htmlToPDF.js文件
import html2Canvas from 'html2canvas'
import JsPDF from 'jspdf'
var noTableHeight = 0
export const htmlPdf = (title, html, fileList, type) => {
if (fileList) {
const pageHeight = Math.floor(277 * html.scrollWidth / 190) + 20
for (let i = 0; i < fileList.length; i++) {
const multiple = Math.ceil((fileList[i].offsetTop + fileList[i].offsetHeight) / pageHeight)
if (isSplit(fileList, i, multiple * pageHeight)) {
var _H = ''
if (fileList[i].localName !== 'tr') {
_H = multiple * pageHeight - (fileList[i].offsetTop + fileList[i].offsetHeight)
} else {
_H = multiple * pageHeight - (fileList[i].offsetTop + fileList[i].offsetHeight + noTableHeight) + 20
}
var newNode = getFooterElement(_H)
const divParent = fileList[i].parentNode
const next = fileList[i].nextSibling
if (next) {
divParent.insertBefore(newNode, next)
} else {
divParent.appendChild(newNode)
}
}
}
}
html2Canvas(html, {
allowTaint: false,
taintTest: false,
logging: false,
useCORS: true,
dpi: window.devicePixelRatio * 1,
scale: 1
}).then(canvas => {
var pdf = new JsPDF('p', 'mm', 'a4')
var ctx = canvas.getContext('2d')
var a4w = type ? 277 : 190; var a4h = type ? 190 : 277
var imgHeight = Math.floor(a4h * canvas.width / a4w)
var renderedHeight = 0
while (renderedHeight < canvas.height) {
var page = document.createElement('canvas')
page.width = canvas.width
page.height = Math.min(imgHeight, canvas.height - renderedHeight)
page.getContext('2d').putImageData(ctx.getImageData(0, renderedHeight, canvas.width, Math.min(imgHeight, canvas.height - renderedHeight)), 0, 0)
pdf.addImage(page.toDataURL('image/jpeg', 1.0), 'JPEG', 10, 10, a4w, Math.min(a4h, a4w * page.height / page.width))
renderedHeight += imgHeight
if (renderedHeight < canvas.height) {
pdf.addPage()
}
}
pdf.save(title + '.pdf')
})
}
const getFooterElement = (remainingHeight, fillingHeight = 0) => {
const newNode = document.createElement('div')
newNode.style.background = '#ffffff'
newNode.style.width = 'calc(100% + 8px)'
newNode.style.marginLeft = '-4px'
newNode.style.marginBottom = '0px'
newNode.classList.add('divRemove')
newNode.style.height = (remainingHeight + fillingHeight) + 'px'
return newNode
}
const isSplit = (nodes, index, pageHeight) => {
if (nodes[index].localName !== 'tr') {
noTableHeight += nodes[index].clientHeight
}
if (nodes[index].localName !== 'tr') {
return nodes[index].offsetTop + nodes[index].offsetHeight < pageHeight && nodes[index + 1] && nodes[index + 1].offsetTop + nodes[index + 1].offsetHeight > pageHeight
} else {
return nodes[index].offsetTop + nodes[index].offsetHeight + noTableHeight < pageHeight && nodes[index + 1] && nodes[index + 1].offsetTop + nodes[index + 1].offsetHeight + noTableHeight > pageHeight
}
}
3、在vue中引入并使用
<template>
<div>
<button class="primary-btn" @click="handleExport">导出</button>
<div class="check-wrapper" id="pdfRef">
<div class="page1-box pdfRef">11</div>
<div class="page2-box pdfRef">11</div>
<div class="page3-box pdfRef">11</div>
<div class="page4-box pdfRef">11</div>
<div class="page5-box pdfRef">11</div>
<div class="page6-box pdfRef">11</div>
<div class="page7-box pdfRef">11</div>
<div class="page8-box pdfRef">11</div>
</div>
</div>
</template>
<script setup>
import { htmlPdf } from "@/utils/htmlToPDF.js"
const handleExport = (name) => {
var fileName= '投资评审报告'
const fileList = document.getElementsByClassName('pdfRef')
htmlPdf(fileName, document.querySelector('#pdfRef'), fileList)
}
</script>