需求背景
在项目中有这样一个需求,需要调用其他系统业务API生成页面(canvas)渲染图表,并将图表导出成PDF文件,上传到服务器,并将文件地址,传给第三方业务系统,使第三方业务系统能够通过文件服务器下载该图表PDF文件
具体分析
接上一篇 使用jsPdf 将页面生成PDF文件并自动上传 DEMO(一)
经过上一篇,我们已经能够正确的下载图表生成的PDF文件了,打开后也能正确的预览PDF文件的内容了
但是 依然存在以下问题:
-
如何不下载PDF到本地磁盘,就能上传???
-
如何保证PDF多页面不空白,也就是如何保证canvas列表已经全部渲染???
-
如何保证很多个图表渲染的时候页面不卡顿???
今天这篇我们就针对这其中一些问题进行处理:
先来解决第一个问题:如何不下载PDF到本地磁盘,就能上传???
如何保证不下载就能获取文件呢?
通过查看 jsPDF 文档 我们发现 官方文档讲的并不是很全面,多是一些基本示例。或许是我们有认真在网上找相关文档或文章:
那我们不妨直接去看看源码,源码中肯定有:
我们直接打开仓库下dist 目录
映入眼帘的是众多文件:
有 es, node , umd , polyfills ,min, 等各种文件; 我们也不纠结具体看什么规范的文件了,随便找一个就是:就看第一个文件 jspdf.es.js
经过我们大致的浏览先找到 save 方法, 这方法我们熟啊,前面才用过的
大概在 Line:3843 的位置
......
case "save":
API.save(options.filename);
break;
.....
嗯, 没错, 很像那么回事 继续跟进API.save 方法 Line:6426 行
/**
* Saves as PDF document. An alias of jsPDF.output('save', 'filename.pdf').
* Uses FileSaver.js-method saveAs.
*
* @memberof jsPDF#
* @name save
* @function
* @instance
* @param {string} filename The filename including extension.
* @param {Object} options An Object with additional options, possible options: 'returnPromise'.
* @returns {jsPDF|Promise} jsPDF-instance */
API.save = function (filename, options) {
filename = filename || "generated.pdf";
options = options || {};
options.returnPromise = options.returnPromise || false;
if (options.returnPromise === false) {
saveAs(getBlob(buildDocument()), filename);
if (typeof saveAs.unload === "function") {
if (globalObject.setTimeout) {
setTimeout(saveAs.unload, 911);
}
}
return this;
} else {
return new Promise(function (resolve, reject) {
try {
var result = saveAs(getBlob(buildDocument()), filename);
if (typeof saveAs.unload === "function") {
if (globalObject.setTimeout) {
setTimeout(saveAs.unload, 911);
}
}
resolve(result);
} catch (e) {
reject(e.message);
}
});
}
}; // applying plugins (more methods) ON TOP of built-in API.
// this is intentional as we allow plugins to override
// built-ins
好家伙,他接受一个filenme 和 options 作为参数
- filename 的缺省值为 generated.pdf
- options 的值默认为{},支持配置 returnPromise 默认 false
我们发现发调用了saveAs 这个API,在方法的描述中他也说了
Uses FileSaver.js-method saveAs.这个 saveAs 是 FileSaver.js 中的 我们这就不去细看 saveAs 返回值了
得,来都来了,不去看一眼,也说不过去了,那就看一眼:
FileSaver 中 saveAs 方法并没有返回值;
Line:144
经过以上我们以为可以通过配置 save 方法的 options.returnPromise = true 拿到Bolo 是不可能的了!
但是,但是,但是细心的我们发现,他传入给saveAs 方法的确是 Bolo;
没错就是这一行:
var result = saveAs(getBlob(buildDocument()), filename);
从 getBlob 这个 函数名 为们发现 我们要的就是这个这个:
到现在 摆在眼前已经有两条路了:
第一: 把这文件拷贝不出来,吧 blob 用一个函数 导出来,供我们自己使用;
第二: 继续找看有没有直接提供相应的API:
权衡过后 我们选择先看第二,第一作为最后的倔强
那就继续浏览代码: 仔细的我们发现API这个类肯定是暴露给用户使用的,我们继续找 我们发现了 一个 output 的方法,看这命名 应该是大体不会差了;
找了一会儿 看到了Line 3828 output 的实现
Line:3850
....
case "blob":
return getBlob(buildDocument());
....
这正是我们寻找的 Blob 对象
那我们知道了 使用output方法 可以拿到了 Blob 对象 剩下的水道渠成了
将 Blob 转 成 file
调用 上传 API 就能直接上传了
参考代码
//Blob 转 file 并上传
function uploadFile(pdfDoc){
const filename = 'xxx.pdf'
const blob = pdfDoc.output('blob',{filename})
const file = new File([blob],filename,{type:blob.type})
const formData = new FormData()
formData.append('file',file)
API.upload(formData).then((res)=>{
const fileId = res.data
// TODO 同步给第三方
})
}
截止现在 我们已经实现了转pdf并上传文件服务器,将结果同步给第三方的多有操作了
下一篇 我们将讨论用什么方式渲染多张图表不卡顿,目前的v-for 方式会导致页面卡顿或浏览器崩溃 查看下上篇 使用jsPdf 将页面生成PDF文件并自动上传 DEMO(一) 查看下一篇 使用jsPdf 将页面生成PDF文件并自动上传 DEMO(三)
最后的最后
请出今天的主角 小趴菜