指定页面中导出为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 pixels
let 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 pixels
let 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 } = config
const zip = new JSZip();
const cache = {};
let downloadStatus = false
const 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 = true
return {
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();
}