pdf 文件预览功能;中文,签名不显示解决;卡顿,渲染慢,崩溃解决;


在这里插入图片描述
在这里插入图片描述

第一种方法:vue-pdf,

安装vue-pdf插件
执行指令:npm install vue-pdf --save

import pdf from "vue-pdf";
<pdf v-for="i in numPages" :key="i" :src="src" :page="i"></pdf>
data() {
    return {
      src: "pdf文件加载路径",
      numPages: undefined,
    };
  },
this.src = pdf.createLoadingTask({
          url: this.pdfData.url
        });
        this.src.promise
          .then(pdf => {
            this.numPages = pdf.numPages;
          })
          .catch(err => {
            console.log("err", err);
          });

注意:这样写并没有结束。大部分pdf可正常显示,但是对一些发票pdf文件内容缺失。还要进行修改
对上面的代码进行修改

import pdf from "vue-pdf";
import CMapReaderFactory from "vue-pdf/src/CMapReaderFactory.js";
this.src = pdf.createLoadingTask({
          url: this.pdfData.url,
          CMapReaderFactory
        });
        this.src.promise
          .then(pdf => {
            this.numPages = pdf.numPages;
          })
          .catch(err => {
            console.log("err", err);
          });

这种方法简单,但是缺点是如果PDF文件非常大。导致整个浏览器崩溃

补充:可以实现大文件滚动分页渲染解决浏览器崩溃问题

在包裹pdf显示外层div添加滚动事件

document
          .getElementById(_this.overflowId)
          .addEventListener("scroll", _this.scrool);
this.src = pdf.createLoadingTask({
          url: this.pdfData.url
        });
        this.src.promise
          .then(pdf => {
           //  this.numPages = pdf.numPages;
          // 重点:这里初始渲染的页数不需要显示总页数,可以自己定义设置想要的页数如初始显示15页,显示少一些就不会卡顿了
          this.totalPage = pdf.numPages
           this.numPages = 15
          })
          .catch(err => {
            console.log("err", err);
          });
scrool() {
      // 滚动渲染pdf下一页
      let _this = this;
      const el = document.getElementById(this.overflowId);
      const offsetHeight = el.offsetHeight;
      el.onscroll = () => {
        const scrollTop = el.scrollTop;
        const scrollHeight = el.scrollHeight;
        if (offsetHeight + scrollTop - scrollHeight >= -1) {
	        //  在这里处理判断这个逻辑滚动渲染接下来的页面
	         if( this.numPages< this.totalPage){
	            this.numPages++
			}
        }
      };
    },

第二种方法:pdf.js

网上下载pdf.js相关库文件,下载地址:https://mozilla.github.io/pdf.js/getting_started/#download

下载pdf.min.js,pdf.worker.min.js两个文件(版本@2.8.335),也可以直接线上引用,我这里是下载到本地

 <script src="/pdfJS/pdf.min.js"></script>
    <script src="/pdfJS/pdf.worker.min.js"></script>
data() {
    return {
      loadedRatio: 0, // 进度
      isError: false, // 搜索pdf文件数据出错
      idTemplate: "cw-pdf-", //创建pdf每一页的canvas的id统一前半部分名称
      indexOfPage: 1, // 页码
      pdfPage: null, // 每一页的数据对象
      totalPage: 0 // 总共页数,
    };
  },
mounted() {
    this.$nextTick(() => {
      document
        .getElementById(this.overflowId)
        .addEventListener("scroll", this.scrool);
      this.isError = false;
      this.loadedRatio = 0;
      this.loadPDF();
    });
  },
scrool() {
      // 滚动渲染pdf下一页
      let _this = this;
      const el = document.getElementById(this.overflowId);
      const offsetHeight = el.offsetHeight;
      el.onscroll = () => {
        const scrollTop = el.scrollTop;
        const scrollHeight = el.scrollHeight;
        if (offsetHeight + scrollTop - scrollHeight >= -1) {
          _this.indexOfPage++;
          if (_this.indexOfPage <= this.totalPage) {
            let id = _this.idTemplate + _this.indexOfPage;
            //根据页码创建画布
            _this.createSeriesCanvas(id);
            //将pdf渲染到画布上去
            _this.renderPDF(_this.pdfPage, _this.indexOfPage, id);
          }
        }
      };
    },
    loadPDF() {
      let _this = this;
      var url = this.pdfData.url;
      // pdfjsDistBuildPdf.GlobalWorkerOptions.workerSrc = "/pdfJS/pdf.worker.js";
      var loadingTask = pdfjsLib.getDocument({
        url: url,
        cMapUrl: "https://unpkg.com/pdfjs-dist@2.8.335/cmaps/",
        cMapPacked: true
      });
      loadingTask.onProgress = function(evt) {
        _this.$set(_this, "loadedRatio", evt.loaded / _this.pdfData.size);
      };
      loadingTask.promise
        .then(function(pdf) {
          //用 promise 获取页面
          _this.pdfPage = pdf;
          var id = "";
          var pageNum = pdf.numPages;
          _this.totalPage = pageNum;

          let length = 15; //初始默认显示15页
          if (pageNum < length) {
            length = pageNum;
          }
          for (let i = 1; i <= length; i++) {
            _this.indexOfPage = i;
            id = _this.idTemplate + i;
            //根据页码创建画布
            _this.createSeriesCanvas(id);
            //将pdf渲染到画布上去
            _this.renderPDF(pdf, i, id);
          }
        })
        .catch(err => {
          let msg = this.lang["abnormal-data"];
          if (document.getElementById("pdf-container")) {
            document.getElementById(
              "pdf-container"
            ).innerHTML = `<div class='text-center' style='color:red;line-height:80px;'>${msg}</div>`;
          }
          this.loadedRatio = 0;
          this.isError = true;
        });
    },
    renderPDF(pdf, i, id) {
      console.log(i, id);
      pdf.getPage(i).then(function(page) {
        let scale = 2.5;
        var viewport = page.getViewport({ scale: scale });

        let popWidth = document.getElementById("pdf-container")
          ? document.getElementById("pdf-container").offsetWidth
          : 0;
        //判断当前弹框的宽度小于PDF文件的宽度时,将viewport和scale的值重新2倍赋值
        if (popWidth && popWidth < viewport.width) {
          scale = (popWidth / viewport.width) * 2.5;
          viewport = page.getViewport({ scale: scale });
        }

        var canvas = document.getElementById(id);
        var context = canvas.getContext("2d");

        canvas.height = viewport.height;
        canvas.width = document.getElementById("pdf-container").offsetWidth;

        var renderContext = {
          canvasContext: context,
          viewport: viewport
        };
        page.render(renderContext);
      });
    },
    createPdfContainer(id, className) {
      var pdfContainer = document.getElementById("pdf-container");
      var canvasNew = document.createElement("canvas");
      canvasNew.id = id;
      canvasNew.className = className;
      var br = document.createElement("br"); //添加上br元素,防止页面变大时候pdf并排显示
      pdfContainer.appendChild(br);
      pdfContainer.appendChild(canvasNew);
    },
    createSeriesCanvas(idTemplate) {
      this.createPdfContainer(idTemplate, "pdfClass");
    }

注意:代码中,这cMapUrl,cMapPacked两个是重点关注,这两个是处理发票内不显示的中文等缺失的内容,cMapUrl内的加载的是这个版本内cmaps文件夹中所有的.bcmap文件,也可以下载到本地项目中引入

  var loadingTask = pdfjsLib.getDocument({
        url: url,
        cMapUrl: "https://unpkg.com/pdfjs-dist@2.8.335/cmaps/",
        cMapPacked: true
      });

之前参照网上其他的写法(如下)是无法起作用的。不知道是不是版本原因

      pdfjsLib.cMapUrl = "https://unpkg.com/pdfjs-dist@2.8.335/cmaps/";
      pdfjsLib.cMapPacked = true;
      var loadingTask = pdfjsLib.getDocument(url);

这个方法相对复杂。可以加载完大文件后对数据进行处理,采用分页滚动加载显示,解决浏览器卡顿,渲染慢,崩溃问题。缺点:移动端会导致内容模糊严重,可能是scale,widht,height等配置不适合问题。

补充1:
发现新问题:huawei mate 40 pro手机 google浏览器 打开发现加载不出pdfjsLib对象。貌似其他部分手机也出现。不知道是不是新手机还是新的google版本的出现这个问题,华为自带的浏览器是可以打开pdf文件,没有问题。有解决方法的,欢迎指教

解决:pdf.js使用2.8.335(2021)版本发现有些移动google浏览器不能打开,还原使用2020年的相关版本解决问题。

Logo

前往低代码交流专区

更多推荐