主要讲一下,在日常项目中用到的关于PDF的一些操作
一、动态生成PDF
1、使用jsPDF + html2canvas
整体流程大致是:
-
安装jsPDF
npm install jspdf
代码中:
import jsPDF from 'jspdf';
import Html2canvas from "html2canvas";
2) 在HTML中绘制DOM
将你需要绘制的PDF内容,在一个区域内通过DOM绘制下来。这个过程中需要注意的是,对于页面中跨域的图片,需要转成base64格式。
// 将跨域图片转换为base64格式
toBase64List = (srcList, typeUrl, _this) => {
function getBase64Image(img, i, description) {
let canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
let ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
let result = _this.state[typeUrl] || [];
result[i] = { url: canvas.toDataURL(), description } ;
_this.setState({ [typeUrl]: result });
}
srcList.forEach((item, i) => {
let image = new Image();
image.crossOrigin = '';
image.src = item.url;
if (item.url) {
image.onload = function () {
getBase64Image(image, i, item.description);
}
}
});
}
3) 通过 html2canvas 将页面DOM转换成图片;
let canvas = await Html2canvas(document.querySelector("#cover"), { scale: 1 });
这个转换的方法写起来很简单,但是html2canvas其实做了很多工作,包括一些资源的下载,例如字体等,如果字体非常大,可以明显看到这个过程非常的慢。
- 通过jspdf将图片导出为pdf文件;
指定需要的PDF是横版还是竖版,使用的单位,以及是A4还是其他板式。
let doc = new jsPDF('l', 'pt', 'a4');
doc.addPage(); // 新增一页
通过addPage新增一页,然后将图片添加到doc中
const [x, y, width, height] = [0, 0, 1000.63, 708.66];
doc.addImage(canvas.toDataURL("image/jpg"), 'JPEG', x, y, width, height);
最后通过save方法直接唤起浏览器的保存PDF的界面
let result = await doc.save(`我是一个PDF文件.pdf`, { returnPromise: true });
整体流程清晰明了,就是先中转为图片,再通过图片转换成PDF文件。
因为jsPDf的官方文档并不稳定,很多时候无法访问,这里建议还是直接看jsPDf的源码,其实很简单。
2、其他方式待补充
当然还有其他的一些方式,以后有所尝试会在这里补充。
二、PDF文件在页面的展示
1 打印PDF文件
先在页面中通过iframe引入pdf文件,然后通过print方法唤起打印。
<iframe style={{width: '100%', height: '80vh'}} title='第1份文件' id="iframeName" src={url} />
const printIframe = document.getElementById('iframeName');
printIframe.contentWindow.print();
注意:如果PDF文件跨域,需要事先去通过ajax请求获取文件,然后转换成Blob格式。
如果只是需要打印功能,PDF文件不想在页面展示,只要把iframe的样式display设置为none,就能在更为友好的情况下实现PDF的打印功能
const blob = new Blob([res.data], { type: 'application/pdf' });
let url = URL.createObjectURL(blob);
2 展示PDF文件
1)iframe元素,如上例子,不多讲。ios手机端不能缩放,需要通过修改CSS样式来调整。
<iframe
style={{ width: '100%', height: '80vh'}}
title="PDF文件"
id="Iframe"
src={pdfUrl}
/>
如果只是纯展示,直接使用PDF路径,如果需要在外部对PDF文件进行打印,可以通过js获取PDF文件流,转成base64格式的路径来使用,避免iframe的跨域问题,视情况而定。
new Promise((resolve, reject): void => {
axios({
baseURL: XXX,
method: 'GET',
url,
params,
responseType: 'blob'
}).then((res): void => {
let blob = new Blob([res.data], { type: 'application/pdf' });
resolve(URL.createObjectURL(blob)); }).catch((err): void => {
reject(err);
});
});
2)embed元素,但是手机端浏览器有兼容问题,可能无法使用。
HTML <embed> 元素将外部内容嵌入文档中的指定位置,但是MDN上有提到,大多数现代浏览器已经弃用并取消了对浏览器插件的支持,所以建议尽量少用或者不用<embed>元素。
<embed
type="application/pdf"
src={pdfUrl}
title={pdfName}
style={{ height: '100vh' }}
/>
适合纯PDF文件展示。
3)PDFjs库 ,将PDF文件转换成canvas,然后可以正常展示在HTML页面中。
pdf.js库是一款功能强大的PDF文件操作库,这里就不细讲,可以关注官网的相关例子,原理是通过canvas实现展示效果,这是和上面几个例子不同的地方,好处就是,可以进一步对PDF文件进行修改,比较灵活。
如果想要进一步实现打印效果,就需要比较好的CSS功底,通过样式的调整,来实现打印页面与当前预览界面区别。
@media print {
@page {
margin: 7mm 0 !important;
padding: 0;
}}