前言
在工作中遇到了一个需求,就是把前端页面生成pdf并保存在本地,因为前端网站可能会展示各种表格,图表信息内容并带有比较鲜艳的色彩样式,如果让后端生产的pdf的话样式可能和前端页面展示的有所差异,所以这个任务就落到了前端的身上。
技术涉及
- jspdf
html2canvas
ali-oss
代码实现
1、获取dom结点
首先需要获取需要打印的dom结点,这个时候获取的dom结点是带有样式的,就相当于页面中的内容
const elehtml = document.queryselector('.zxksbody');2、获取打印容器的属性
首先做个兼容判断,判断是否取到了dom结点信息,如果取到了dom结点就获取dom结点的内容,进行高度和宽度的赋值
if (elehtml) {
let elew = elehtml.offsetwidth; // 获得该容器的宽
let eleh = elehtml.offsetheight; // 获得该容器的高
}
3、生成pdf
这一步就是把获取到的dom结点,通过jspdf和html2canvas 生成为pdf
html2canvas(elehtml, {
dpi: 300,
width: elew,
height: eleh,
scale: 2, // 提高渲染质量
usecors: true //允许canvas画布内 可以跨域请求外部链接图片, 允许跨域请求。
}).then(async (canvas) => {
const pdf = new jspdf('', 'pt', 'a4');
const imgdata = canvas.todataurl('image/png', 1.0);
//a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
const imgwidth = 555.28;
//一页pdf显示html页面生成的canvas高度;
const imgheight = 555.28 / canvas.width * canvas.height;
// 计算分页
const pageheight = 841.89;
//未生成pdf的html页面高度
let leftheight = imgheight;
//页面偏移
let position = 0;
if (leftheight < pageheight) {
//在pdf.addimage(pagedata, 'jpeg', 左,上,宽度,高度)设置在pdf中显示
pdf.addimage(imgdata, 'png', 20, 20, imgwidth, imgheight);
} else { // 分页
while (leftheight > 0) {
pdf.addimage(imgdata, 'png', 20, position, imgwidth, imgheight);
leftheight -= pageheight;
position -= 841.89;
if (leftheight > 0) {
pdf.addpage();
}
}
});4、保存本地或者上传oss
保存本地
保存本地的话比较简单,直接调用pdf库自带的方法就可以保存到本地
pdf.save(`${state.xsmc}-${state.xsbh}.pdf`)上传oss
上传的oss的话就比较复杂一点,首先就是需要配置oss的内容,然后把pdf转换为blob对象,最后就是调用oss的接口实现上传。
// 配置oss
const client = new oss({
region: "******",
bucket: 'bucketname',
endpoint: 'endpoint',
ststoken: 'securitytoken',
accesskeyid: 'accesskeyid',
accesskeysecret: 'accesskeysecret',
});
// 将 pdf 文件转换为 blob 对象
const pdfblob = pdf.output('blob');
// 调用oss上方实现上传
const fileres = await client.put(`${state.xsmc}-${state.xsbh}.pdf`, pdfblob);
console.log(fileres, '接收返回的oss信息');5、注意事项
- 使用html2canvas和jspdf可能会遇见文本错位或者样式错误问题,这个时候需要进行调整,可以通过html2canvas中的onclone回调方法进行调整
html2canvas(elehtml, {
onclone: (documentclone) => {
// 在克隆的文档上进行修改
const partright2 = documentclone.queryselector('.partright2');
const titlebars = documentclone.queryselectorall('.titlebar');
if (partright2) {
partright2.style.display = 'none'; // 隐藏内容
}
if (titlebars) {
//修改样式属性
titlebars.foreach(titlebar => {
titlebar.style.margintop = '-8px';
titlebar.style.marginbottom = '20px';
});
}
},
dpi: 300,
width: elew,
height: eleh,
scale: 2, // 提高渲染质量
usecors: true //允许canvas画布内 可以跨域请求外部链接图片, 允许跨域请求。
}).then(async (canvas) => {
.......
});- 对于在获取dom时,带有滚动条的内容无法正确获取他的高度和宽度,内容可能会被遮盖无法正确打印,这个时候需要在打印前更改页面中的dom样式才能正确打印
// 获取全部内容
const elehtml = document.queryselector('.zxksbody');
// 在生成canvas之前就把样式进行更改,获取盒子的正常高度或者宽度,防止样式被遮盖,
const changeheight = document.queryselector('.zxkscontent');
if (changeheight) {
changeheight.style.height = '100%'; // 更改高度
}
html2canvas(elehtml, {
dpi: 300,
width: elew,
height: eleh,
scale: 2, // 提高渲染质量
usecors: true //允许canvas画布内
}).then(async (canvas) => {
.....
// 在打印完成后,再把样式改回去
if (changeheight) {
changeheight.style.height = 'calc(100vh - 182px)';
}
}
- 对于带有滚动条的div盒子,在点击打印时,最好把页面内容进行更改,防止无法正确获取盒子高度,导致文字被隐藏,在打印完成后,在更改回去
// 对于vue
可以使用v-if进行更换,把展示的内容保存在div中,去掉溢出滚动功能
// 对于react
可以使用三元运算符进行判断,展示的内容
6、完整代码
const printpdf = async () => {
const client = new oss({
const client = new oss({
region: "******",
bucket: 'bucketname',
endpoint: 'endpoint',
ststoken: 'securitytoken',
accesskeyid: 'accesskeyid',
accesskeysecret: 'accesskeysecret',
});
try {
// 获取全部内容
const elehtml = document.queryselector('.zxksbody');
// 带有移除隐藏的功能
const changeheight = document.queryselector('.zxkscontent');
if (changeheight) {
changeheight.style.height = '100%'; // 更改高度
}
if (elehtml) {
let elew = elehtml.offsetwidth; // 获得该容器的宽
let eleh = elehtml.offsetheight; // 获得该容器的高
// 确保获取加载完全的dom
settimeout(() => {
html2canvas(elehtml, {
onclone: (documentclone) => {
// 在克隆的文档上进行修改
const partright2 = documentclone.queryselector('.partright2');
const titlebars = documentclone.queryselectorall('.titlebar');
if (partright2) {
partright2.style.display = 'none'; // 隐藏内容
}
if (titlebars) {
titlebars.foreach(titlebar => {
titlebar.style.margintop = '-8px';
titlebar.style.marginbottom = '20px';
});
}
},
dpi: 300,
width: elew,
height: eleh,
scale: 2, // 提高渲染质量
usecors: true //允许canvas画布内 可以跨域请求外部链接图片, 允许跨域请求。
}).then(async (canvas) => {
const pdf = new jspdf('', 'pt', 'a4');
const imgdata = canvas.todataurl('image/png', 1.0);
const imgwidth = 555.28;
const imgheight = 555.28 / canvas.width * canvas.height;
// 计算分页
const pageheight = 841.89;
let leftheight = imgheight;
let position = 0;
if (leftheight < pageheight) {
pdf.addimage(imgdata, 'png', 20, 20, imgwidth, imgheight);
} else {
while (leftheight > 0) {
pdf.addimage(imgdata, 'png', 20, position, imgwidth, imgheight);
leftheight -= pageheight;
position -= 841.89;
if (leftheight > 0) {
pdf.addpage();
}
}
}
// 将 pdf 文件转换为 blob 对象
const pdfblob = pdf.output('blob');
// 使用 oss 客户端上传 blob 对象
try {
const fileres = await client.put(`${state.xsmc}-${statexsbh}.pdf`, pdfblob);
console.log('client res', fileres);
} catch (err) {
console.error('pdf上传失败,请重新提交!', err);
}
if (changeheight) {
changeheight.style.height = 'calc(100vh - 182px)';
}
});
}, 1000);
}
} catch (error) {
console.log("error!", error);
if (changeheight) {
changeheight.style.height = 'calc(100vh - 182px)';
}
}
};总结
到此这篇关于纯前端生成pdf(jspdf)并下载保存或上传到oss的文章就介绍到这了,更多相关 前端生成pdf并下载保存或上传到oss内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论