pdf.js可以通过链接和流的方式展示pdf,由于后台接口不想保存缓存文件生成链接,直接返回流的方式在pdf.js中展示,链接比较方便简单,但是流的方式相对就比较繁琐。
项目中vue->html大概流程:
vue通过html模板参数调用pdf生成接口->返回pdf流传参给pdf.js->pdf.js解析展示。
起初的实现方式sessionStore保存pdf流:
vue中通过sessionStore保存返回的pdf流数据,在pdf.js中获取然后解析。实现结果是可以的,但是存在一个sessionStore存储大小5M限制问题,如果后台返回的流大于5M,就不能正常显示。
间接实现方式sessionStore保存pdf生成参数:
通过sessionStore传入生成pdf的参数(html code),在pdf.js中调用接口返回流并解析展示pdf。该实现方式同样存在生成的pdf参数大于5M的情况,尤其是参数中如果嵌入图片就难免会大于5M。
通过vuex共享方式
没有搞定,放弃。
最终方式通过postMessage传参的方式:
// vue 代码
// 获取pdf.js 嵌入的iframe
let pdfViewerFrame = document.getElementById("pdfViewer");
let _pdfViewerFrame = document.getElementById("pdfViewer").contentWindow;
axios.post(
'获取pdf的接口url'
// 生成pdf的参数数据
{ data: this.jsonData, thtml: this.elHtmlCode },
{})
.then((res) => {
// 注释部分为原有实现方式
//sessionStorage.setItem("pdfData", res.data.content.filedata);
pdfViewerFrame.src = "./pdfjs/web/pdfviewer.html";
// 防治异步未加载成功
pdfViewerFrame.onload = function(){
// 加载成功后传递pdf base64数据
_pdfViewerFrame.postMessage(res.data.content.filedata, '*');
};
}).catch(function (error) {
console.log(error);
});
// pdfjs pdfviewer.html中部分代码
var DEFAULT_URL = "";
var BASE64_MARKER = ';base64,';//声明文件流编码格式
var preFileId = "";
var pdfAsDataUri;
var pdfAsArray;
// 监听获取postMessage中的参数
window.addEventListener("message", function(event){
// pdf数据 base64(没有base64前缀)
var data = event.data;
this.pdfAsDataUri = data;
this.pdfAsArray = convertDataURIToBinary(pdfAsDataUri);
this.DEFAULT_URL = pdfAsArray;
console.log(DEFAULT_URL)
// viewer.js用于渲染pdf数据的,默认读取DEFAULT_URL,如果初始化时DEFAULT_URL没有数据则渲染会失败,这里存在异步的问题,因此需要改为动态加载viewer.js
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.src = "viewer.js";
script.type = 'text/javascript';
head.appendChild(script);
});
// pdf流数据转换
function convertDataURIToBinary(dataURI) {
//编码转换
var raw = window.atob(dataURI);//这个方法在ie内核下无法正常解析。
var rawLength = raw.length;
//转换成pdf.js能直接解析的Uint8Array类型
var array = new Uint8Array(new ArrayBuffer(rawLength));
for (i = 0; i < rawLength; i++) {
array[i] = raw.charCodeAt(i) & 0xff;
}
return array;
}
关键的几点:
- 调用postMessage的方法对象是_pdfViewerFrame,而非pdfViewerFrame。
- “pdfViewerFrame.onload” pdf加载后再调用postMessage,防止异步传参失败。
- pdfviewer.html中“viewer.js” 动态加载,也是异步问题,起初iframe加载pdfviewer.html是没有pdf数据,是无法渲染的,因此需要在获取到解析后pdf数据后再渲染。
至此pdf通过流数据方式的展示不再受大小限制了。