指定页面中导出为pdf格式并打包,使用html2canvas先转为图片格式,在利用jspdf转为pdf,最后下载打包为本地压缩包
yarn add html2canvas
yarn add jspdf
1. 注册一个插件并挂载
import html2Canvas from 'html2canvas'
import JsPDF from 'jspdf'
export default {install(Vue, options) {Vue.prototype.getPdf = function (dom) {return new Promise((resolve, reject) => {html2Canvas(dom.$el, {allowTaint: true,scale: 2,dpi: 300,}).then(function (canvas) {let contentWidth = canvas.width;let contentHeight = canvas.height;let pdfWidth = 595.28; // A4 width in pixelslet pdfHeight = (pdfWidth / contentWidth) * contentHeight;let pageData = canvas.toDataURL('image/jpeg', 1.0);let PDF = new JsPDF('p', 'pt', 'a4');let scale = pdfWidth / contentWidth;PDF.addImage(pageData, 'JPEG', 0, 0, pdfWidth, pdfHeight);let remainingHeight = pdfHeight;while (remainingHeight < contentHeight) {PDF.addPage();let offsetY = -remainingHeight * scale;PDF.addImage(pageData, 'JPEG', 0, offsetY, pdfWidth, pdfHeight);remainingHeight += pdfHeight;}PDF.save('export.pdf'); //直接下载// resolve(PDF.output('blob')); //转为blob格式 返回合并下载}).catch(reject);});};}
}
2. 页面使用
DownPDFAndFile(){this.getPdf('传入ref或者是id')
}
以上正常导出步骤 封装方法 使用 但是如果你的项目中用的是rem布局或者是适配方法,样式或者字体没有显示出来被盖掉请往下看
3.由于在项目中用rem做了适配导致样式变形
4. 我们可以在html2canvas生成图片时把对应的样式或者添加类名,在生成图片前修改样式,转换为pdf后恢复初始样式
import html2Canvas from 'html2canvas'
import JsPDF from 'jspdf'
/*** @param {*} 添加样式类名*/
function removeChildrenWithClass(parent, className) {var children = parent.childNodes;if (parent.classList && parent.classList.contains('form_view_item')) {parent.childNodes.forEach((item) => {item.className += ' is_to_print'})}for (var i = 0; i < children.length; i++) {if (children[i].classList && children[i].classList.contains('isprint')) {children[i].style.display = 'block'if (children[i].classList.contains('is_toprint')) children[i].style.display = 'block'}if (children[i].classList && children[i].classList.contains('form_view_title')) {children[i].style.marginTop = '25px'}if (children[i].classList && children[i].classList.contains(className)) {children[i].style.display = 'none'} else if (children[i].childNodes) {removeChildrenWithClass(children[i], className);}}
}
/*** @param {*} 恢复初始样式*/
function restoreOriginalState(parent, className) {var children = parent.childNodes;if (parent.classList && parent.classList.contains('form_view_item')) {parent.childNodes.forEach((item) => {item.classList.remove('is_to_print');});}for (var i = 0; i < children.length; i++) {if (children[i].classList && children[i].classList.contains(className)) {children[i].style.display = '';}if (children[i].classList && children[i].classList.contains('form_view_title')) {children[i].style.marginTop = '';}if (children[i].classList && children[i].classList.contains('isprint')) {children[i].style.display = 'none';}if (children[i].childNodes) {restoreOriginalState(children[i], className);}}
}
export default {install(Vue, options) {Vue.prototype.getPdf = function (dom) {return new Promise((resolve, reject) => {removeChildrenWithClass(dom.$el, 'noprint');html2Canvas(dom.$el, {allowTaint: true,//如果不要求清晰度可以去掉scale: 2, //按比例增加分辨率 dpi: 300, //将分辨率提高到特定的 DPI}).then(function (canvas) {restoreOriginalState(dom.$el, 'noprint')let contentWidth = canvas.width;let contentHeight = canvas.height;let pdfWidth = 595.28; // A4 width in pixelslet pdfHeight = (pdfWidth / contentWidth) * contentHeight;let pageData = canvas.toDataURL('image/jpeg', 1.0);let PDF = new JsPDF('p', 'pt', 'a4');let scale = pdfWidth / contentWidth;PDF.addImage(pageData, 'JPEG', 0, 0, pdfWidth, pdfHeight);let remainingHeight = pdfHeight;while (remainingHeight < contentHeight) {PDF.addPage();let offsetY = -remainingHeight * scale;PDF.addImage(pageData, 'JPEG', 0, offsetY, pdfWidth, pdfHeight);remainingHeight += pdfHeight;}PDF.save('export.pdf'); //直接下载// resolve(PDF.output('blob')); //转为blob格式 返回合并下载}).catch(reject);});};}
}
5. 修改完后导出正常
6. 如果需求是直接下载以下就忽略,如果需求是打包为本地压缩包请继续
// 引入使用attachDownload方法
// 下载事件
async DownPDFAndFile() {const pdfinfo = await this.getPdf('传入ref或者是id')const pdfList = [//参数字段自行修改 为attachDownload 中的字段对应{id: "...",data: pdfinfo,},];const ImageList = []const VideoList = []const ImageAndVideoAndPdfList = [...pdfList,...ImageList,...VideoList]const { downloadStatus } = await this.is_downFile(ImageAndVideoAndPdfList);// downloadStatus 这个状态为下载状态 true为完成 可以自行添加业务},
// 下载方法
async is_downFile(list) {if (list.length > 0) {const config = {downloadList: list,suffix: "病历编辑.zip",};const { downloadStatus } = await attachDownload(config);return { downloadStatus };}},
7. 打包下载使用的是JSZip 和 FileSaver
yarn add jszip
yarn add file-saver
// attachDownload.js
import JSZip from "jszip";
import FileSaver from "file-saver";
export async function attachDownload(config) {const { downloadList, suffix } = configconst zip = new JSZip();const cache = {};let downloadStatus = falseconst downloadPromises = downloadList.map(async (item) => {try {if (item.url) {let data;if(item.type=='.pdf'){data = item.data;}else{data = await getImgArrayBuffer(item.url);}zip.folder(suffix).file(`${item.Title}_${item.FileID}` + item.type, data, { binary: true });cache[item.id] = data;} else {throw new Error(`文件${item.fileName}地址错误,下载失败`);}} catch (error) {console.error("文件获取失败", error);}});try {await Promise.all(downloadPromises);const content = await zip.generateAsync({ type: "blob" });FileSaver.saveAs(content, suffix);downloadStatus = truereturn {downloadStatus}} catch (error) {console.error("文件压缩失败", error);}
}
async function getImgArrayBuffer(url) {const response = await fetch(url);if (!response.ok) {throw new Error(`请求失败: ${response.status}`);}return await response.blob();
}