安装以下5个依赖包
npm i html2canvas
npm i jspdf
npm i print-js
npm i jszip
npm i file-saver
新建文件pdfUtils.js
import {ElLoading} from "element-plus";
import html2canvas from "html2canvas";
import jsPDF from "jspdf";
import printJS from "print-js";
import JSZip from "jszip";
import FileSaver from "file-saver";
/**
* @desc html转canvas
* @param {HTMLElement} element 需要转换的html节点
* @auth roffer
* @date 2024/10/23 10:12
*/
export const htmlToCanvas = async (element) => {
const oldOffsetHeight = element.offsetHeight
//是否包含滚动条
const isScroll = element.scrollHeight > oldOffsetHeight
if (isScroll) {
//如果包含滚动条,重新设置元素的高度,让其显示完整,因为html2canvas不能输出滚动条以外的内容
element.style.height = element.scrollHeight + "px"
}
const options = {
// useCORS: true,
// dpi: window.devicePixelRatio * 1, //dpi属性的值为192,表示图像的分辨率
// scale: 4, //scale属性的值为2,表示图像的缩放比例。
// backgroundColor: "#F1F6FE" //backgroundColor属性的值为"#F1F6FE",表示图像的背景颜色。
}
const canvas = await html2canvas(element, options)
// const data = canvas.toDataURL('image/png')
if (isScroll) {
//处理完成之后还原之前的高度
element.style.height = oldOffsetHeight + "px"
}
return canvas
}
/**
* @desc 打印html节点
* @param {String} selector 需要转换的html节点选择器: .xxx #xxx
* @auth roffer
* @date 2024/10/23 10:33
*/
export const printHTML = async (selector) => {
const element = document.querySelector(selector)
const canvas = await htmlToCanvas(element)
// const pdfFile = await html2PDF(selector)
printJS({
// printable: pdfFile, // 指定要打印内容的元素
// type: 'pdf',//指定打印的类型,pdf、image、html、json、raw-html
// printable: element, // 指定要打印内容的元素
printable: canvas, // 指定要打印内容的元素
type: 'html',//指定打印的类型,pdf、image、html、json、raw-html
// 不打印页眉和页脚,以及解决打印预览多出来的一页空白页,设置:body {margin:0;padding:0}
style: '@page {size: auto;margin: 0 10mm} body {margin:0;padding:0}',
// honorColor: true,// 是否打印彩色文本
// scanStyles: true,
// base64:true,//当type为'image'时,将图像转换为base64格式并返回。
// style: '@import "@/components/printTemplates/components/order/windowBinding.scss";' // 指定打印样式文件
// targetStyles: ['*'], // 允许打印所有样式属性
// documentTitle: '文档标题',//指定输出的文档标题。
// header: '统计图',
// css: new URL('@/components/printTemplates/components/order/windowBinding.scss', import.meta.url).href
})
}
/**
* html导出pdf
* @param {Object} option 参数对象
* @param {String} option.selector 需要导出的html节点选择器: .xxx #xxx 如果匹配到多个元素,则会导出多个文件
* @param {Array} option.nameList 导出的文件名称,传递一个数组,因为传递的元素可能会有多个,则会生成多个pdf文件。举例:['name1.pdf','name2,pdf']
* @param {Boolean} option.zip 是否将pdf文件导出zip,默认false
* @auth Roffer
* @date 2024/4/19 15:26
*
*/
export const html2PDF = async (option) => {
const loadingInstance = ElLoading.service({
lock: true,
text: '生成中,请稍后...',
background: 'rgba(0, 0, 0, 0.7)',
})
const {selector,nameList,zip,zipName} = {
zip: false,
zipName:'pdfs.zip',
...option
}
// 创建JSZip实例
let zipPackage = new JSZip()
//获取dom节点
const elementList = document.querySelectorAll(selector)
for (let i = 0; i < elementList.length; i++) {
// 新建jsPDF实例
const pdf = new jsPDF('p', 'px', 'a4')
const element = elementList[i]
//使用html2Canvas插件将dom节点转化成base64
const canvas = await htmlToCanvas(element)
const elementWidth = element.offsetWidth
const elementHeight = element.scrollHeight > element.offsetHeight ? element.scrollHeight : element.offsetHeight
// const elementWidth = canvas.width
// const elementHeight = canvas.height
//图片数据
let imgData = canvas.toDataURL('image/jpeg', 1.0)
//图片宽度
const imgWidth = pdf.internal.pageSize.getWidth()
//图片高度
const imgHeight = (imgWidth / elementWidth) * elementHeight;
//一页高度
const pageHeight = Math.ceil(pdf.internal.pageSize.getHeight())
let position = 0
if (imgHeight <= pageHeight) {
//不足或者刚好够一页的情况
pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight)
} else {
//超出一页的情况,循环判断如果图片高度+移动后的一个单位页高度还小于总高度,说明还有分页,继续进行下一个分页
while (imgHeight + Math.abs(position) < elementHeight) {
pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight)
position -= pageHeight
//处理边界空白情况,防止多出来一个空白页
if (imgHeight + Math.abs(position) < elementHeight) {
pdf.addPage()
}
}
}
if(zip){
// 将blob添加到zip文件中
zipPackage.file(nameList[i], pdf.output('blob'))
}else{
// 保存PDF
pdf.save(nameList[i])
}
}
// 使用JSZip将所有PDF打包成ZIP文件并下载
zip && zipPackage.generateAsync({type: "blob"}).then(function (content) {
FileSaver.saveAs(content, zipName)
})
loadingInstance.close()
}
调用测试
import {printHTML,html2PDF} from './pdfUtils'
//执行打印
const doPrint = () => {
printHTML('#printTemplate')
}
//导出pdf文件
const doExport = () => {
const nameList = ['name1.pdf','name2.pdf']
html2PDF({
selector: '.template',
nameList,
zip: true,
zipName: 'test.zip',
})
}