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(生成pdf的参数主要是html,如果带图片类的,仍然会>5M,但是如果不是这种形式,其实是可以采用这种方式)。

通过vuex共享方式,由于涉及到pdfview.html 原生的js,因此需要嵌入的和改造的比较多,也不知道是否会存在其他影像,因此放弃。

最终方式通过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;
        }

关键的几点:

  1. 调用postMessage的方法对象是_pdfViewerFrame,而非pdfViewerFrame,这里有些文章使用的对象错误,因此无法传参成功。
  2. “pdfViewerFrame.onload” 作用是iframe加载后再调用postMessage,防止异步向iframe子页面传参失败。
  3. pdfviewer.html中“viewer.js” 动态加载,使用动态加载是因为viewer.js是用来渲染pdf的,起初iframe加载pdfviewer.html是没有pdf数据,是无法渲染的,因此需要在获取到解析后的pdf数据后再渲染,也就是再加载viewer.js 才能渲染出pdf。

至此pdf通过流数据方式的展示不再受大小限制了。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐