需求
1、前端自定义 html 模板,导出 pdf
2、多个 pdf 导出压缩到一个文件 zip 里面
原理
1、html2Canvas 将 html 模板转为 canvas
2、canvas 转为 img 图片
3、生成的图片添加到 pdf 里面
用到的插件
html2canvas
jspdf
jszip
file-saver
模板
{{ row.meetingName }}会议纪要
会议主题 |
{{ row.meetingTheme }} |
会议时间 |
{{ meetingTime || '-' }} |
会议地点 |
{{ row.meetingPlace }} |
会议级别 |
{{ matterLevelObj[row.meetingLevel]||"-" }} |
主持人 |
{{ row.host }} |
记录人 |
{{ row.recorder }} |
抄报 |
{{ row.ccleader }} |
审批人 |
{{ row.approverName || '-' }} |
参与人 |
{{ row.participant }} |
备注 |
{{ row.remark }} |
会议内容 |
{{ row.remark }} |
会议事项 |
序号 |
类型 |
工作事项 |
负责人 |
预计完成时间 |
工作计划 |
{{ i+1 }} |
{{ item.type }} |
{{ item.workItem }} |
{{ item.principalName }} |
{{ item.planEndtime }} |
{{ item.workPlan }} |
异步导出函数
async exportMeeting (type) {
// type:'1' 选择导出 'all':导出所有
try {
this.allLoading = true
let selectedData = []
if (type === '1') {
const ids = this.multipleSelection.map(el => el.id)
selectedData = await this.getMeetingAll(ids)
} else if (type === 'all') {
selectedData = await this.getMeetingAll()
}
this.loadingText = '正在拼命导出...'
const zip = new JSZip()
const promises = []
this.isShowPdf = true
for (let i = 0; i < selectedData.length; i++) {
const element = selectedData[i]
this.data = element
// 等待每一个转为pdf
const p = await htmlToPdf.getPdf(document.getElementById('pdf'), element.meetingName)
promises.push(p)
}
// 等到所有的promise执行完成依次压缩到zip中
Promise.all(promises).then(async (pdfs) => {
for (let i = 0; i < pdfs.length; i++) {
const { PDF, name } = pdfs[i]
// 如果只是导出一个pdf,则导出pdf格式
if (pdfs.length === 1) {
PDF.save(`${name}-${new Date().getTime()}.pdf`)
this.allLoading = false
this.loadingText = '正在请求数据'
} else {
// 否则添加到压缩包里面
await zip.file(`${name}-${new Date().getTime()}.pdf`, PDF.output('blob'))
}
}
if (pdfs.length > 1) {
zip.generateAsync({ type: 'blob' }).then(content => {
FileSaver.saveAs(content, '销项管理平台会议纪要.zip')
})
}
}).finally(() => {
this.allLoading = false
this.loadingText = '正在请求数据'
})
} catch (e) {
this.allLoading = false
this.loadingText = '正在请求数据'
throw new Error(e)
}
},
获取 pdf 的公共封装函数
// 导出pdf
import html2Canvas from 'html2canvas';
import JsPDF from 'jspdf';
export default {
getPdf: (el, pdfName) => {
// 滚轮滑动造成的,主要是html2canvas是根据body进行截图,若内容高度高于body时,就会出现这样的问题
// 解决方案:(在生成截图前,先把滚动条置顶)
window.pageYoffset = 0;
document.documentElement.scrollTop = 0;
document.body.scrollTop = 0;
return new Promise((resolve, reject) => {
// 在点击保存图片时,此时要保存的资源较多,造成模块并没有完全加载完毕,就已经生成了截图。
// 解决方案:(延迟)
setTimeout(() => {
// 这句挺重要
html2Canvas(el, {
scale: 4,
dpi: 300,
useCORS: true,
// allowTaint: true
})
.then((canvas) => {
const contentWidth = canvas.width;
const contentHeight = canvas.height;
const pageHeight = (contentWidth / 592.28) * 841.89;
let leftHeight = contentHeight; //
let position = 0;
const imgWidth = 595.28;
const imgHeight = (592.28 / contentWidth) * contentHeight;
const pageData = canvas.toDataURL('image/jpeg', 1.0);
const PDF = new JsPDF('', 'pt', 'a4');
if (leftHeight < pageHeight) {
// 在pdf.addImage(pageData, 'JPEG', 左,上,宽度,高度)设置在pdf中显示;
PDF.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight);
// pdf.addImage(pageData, 'JPEG', 20, 40, imgWidth, imgHeight);
} else {
// 分页
while (leftHeight > 0) {
PDF.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight);
leftHeight -= pageHeight;
position -= 841.89;
// 避免添加空白页
if (leftHeight > 0) {
PDF.addPage();
}
}
}
resolve({ PDF, name: pdfName });
})
.catch((e) => {
reject(e);
});
}, 500);
});
},
};
遇到的问题
zip.file(`${name}-${new Date().getTime()}.pdf`, PDF.output('blob')); //第二个参数PDF.output('blob')
// 通过给文件名添加一个时间戳解决
zip.file(`${name}-${new Date().getTime()}.pdf`, PDF.output('blob')); //`${name}-${new Date().getTime()}.pdf`