pdf的使用和兼容问题

1. 开始使用vue-pdf这个插件, 发现它只适用于页码小的文件, 文件大了容易卡顿奔溃 (建议小文件使用,比较方便)

2. 然后做优化, 在包裹pdf显示外层div添加滚动事件, 初始渲染的页数不要显示总页数,可以自己定义设置想要的页数如初始显示10页,显示少一些卡顿有效缓解, 监听滚动做分页功能。(这种方式在50页以内还行,再大了有些配置低点的机型扛不住,也会卡顿)

3. 因为文件上百页,没办法选择切换插件,选了pdfjs-dist, 这个是没有封装的,自己进行处理, 解决了上面的问题

4. 这里遇到的几个问题,

4.1 vue-pdf和pdfjs-dist引入会出现盖章不显示问题,解决方案:需注释依赖中的部分代码

if (data.fieldType === "Sig") {
  // data.fieldValue = null;
  // this.setFlags(_util.AnnotationFlag.HIDDEN);
}

4.2 vue-fdf 出现二次回显,填充内容不显示问题

//node_modules/vue-pdf/CMapReaderFactory.js
// .then 后面添加  加载完语言文件后清除缓存
delete require.cache[require.resolve('./buffer-loader!pdfjs-dist/cmaps/'+query.name+'.bcmap')]

4.3 部分文字不显示的问题

引入CMapReaderFactory

4.4 移动端放大缩小问题

这里引入了腾讯手势库 AlloyFinger

5. 示例demo

<template>
  <section class="main">
    <article ref="pdfContainer" class="content">
      <div class="pdf_box" ref="pdfBoxDom">
        <canvas
          v-for="index in PDFPageCount"
          v-bind:key="index"
          :ref="'canvas_' + index"
          :style="{ width: scale * pdfWidth + 'px' }"
        ></canvas>
      </div>
    </article>
    <div v-show="isLoading" class="overlay_dialog">
      <van-loading size="44" vertical> 加载中... </van-loading>
    </div>
  </section>
</template>

<script>
// import pdf from 'vue-pdf';
import AlloyFinger from 'alloyfinger';
// 解决部分文字不显示的问题
import CMapReaderFactory from 'vue-pdf/src/CMapReaderFactory.js';
const pdfjsLib = require('pdfjs-dist/es5/build/pdf');
const workerSrc = require('pdfjs-dist/es5/build/pdf.worker.entry.js');

// 防抖 callback 回调函数 ms 周期性执行回调间隔时间ms
function debounce(callback, ms) {
  let timer, isScroll;
  return function () {
    if (isScroll) {
      return;
    }
    isScroll = true;
    timer && clearTimeout(timer);
    timer = setTimeout(() => {
      callback && callback();
      isScroll = false;
      timer = null;
    }, ms);
  };
}

export default {
  name: 'TrustContract',

  // components: { pdf },

  data() {
    return {
      info: {},
      isLoading: false,
      scaleFlag: true, // 是否可缩放

      PDFDocument: null, // PDF 文档类
      PDFPageCount: 0, // PDF 文档总页数
      pdfWidth: 0, // PDF 宽
      pdfHeight: 0, // PDF 高
      pageNumber: 1, // 当前加载的页码
      scale: 1, // PDF 文档缩放倍数
      oldscale: 1,
    };
  },

  created() {
    this.info = this.$route.query || {};
    if (this.info.contractPath) {
      pdfjsLib.GlobalWorkerOptions.workerSrc = workerSrc;
      this.$nextTick(() => {
        this.loadFile();
      });
    }
  },

  mounted() {
    this.getData();
  },

  methods: {
    loadFile() {
      let url = window.customConfig.filePathPdf.url + this.info.contractPath;
      this.isLoading = true;
      pdfjsLib
        .getDocument({ url, CMapReaderFactory })
        .promise.then(
          (PDF) => {
            this.PDFPageCount = PDF.numPages;
            this.PDFDocument = PDF;
            this.$nextTick(() => {
              // 重置元素为未读状态
              Object.keys(this.$refs)
                .filter((tmp) => /canvas.*_\d/.test(tmp))
                .forEach((tmp) => {
                  this.$refs[tmp].isRead = false;
                });
              // 绑定滑动事件
              this.$refs.pdfBoxDom.addEventListener(
                'scroll',
                debounce(this.contentScroll, 200),
                true,
              );
              // 一次性加载10页
              const loadPage = this.PDFPageCount > 5 ? 5 : this.PDFPageCount;
              for (let i = 1; i <= loadPage; i++) {
                this.pageNumber = i;
                this.getPageAndRender();
              }
              this.isLoading = false;
            });
          },
          (e) => (this.isLoading = false),
        )
        .catch((e) => (this.isLoading = false));
    },

    // 滑动展示PDF
    contentScroll() {
      const scrollTop = this.$refs.pdfBoxDom.scrollTop;
      // 获取到下一个未加载的
      const nextPage = this.pageNumber + 1;
      const canvas = this.$refs['canvas_' + nextPage];
      if (!canvas || (canvas && canvas.isRead)) {
        return;
      }
      if (scrollTop > (this.pageNumber - 2) * this.pdfHeight * this.scale - 100) {
        const nextCount = this.pageNumber + 5;
        const loadPage = this.PDFPageCount > nextCount ? nextCount : this.PDFPageCount;
        for (let i = nextPage; i <= loadPage; i++) {
          this.pageNumber = i;
          this.getPageAndRender();
        }
      }
    },

    // 加载PDF图片
    getPageAndRender() {
      // 超过总页数或已隐藏,则不再继续加载
      if (this.pageNumber > this.PDFPageCount) {
        return;
      }
      // 判断是否已加载过
      const canvas = this.$refs['canvas_' + this.pageNumber];
      if (canvas && !canvas.isRead) {
        console.log('getPageAndRender---', this.pageNumber);
        canvas.isRead = true;
        // 获取当前页码PDF的属性并渲染到页面
        this.PDFDocument.getPage(this.pageNumber)
          .then(
            (page) => {
              // 设置视口的所需比例
              const viewport = page.getViewport({ scale: 2 });
              // PDF文件 viewport 成功才继续做渲染操作
              const canvasHtml = canvas && canvas[0];
              if (viewport && viewport.width && canvasHtml && canvasHtml.width) {
                const _width = window.screen.availWidth;
                // 设置画布宽高
                canvasHtml.width = viewport.width;
                canvasHtml.height = viewport.height;
                // 设置缩放比例
                this.scale = this.oldscale = _width / viewport.width;
                console.log(this.scale, 'this.scale456');
                // 储存
                this.pdfWidth = viewport.width;
                this.pdfHeight = viewport.height;
                // 渲染PDF到页面
                page.render({ canvasContext: canvasHtml.getContext('2d'), viewport: viewport });
              }
            },
            (e) => (this.isLoading = false),
          )
          .catch((e) => (this.isLoading = false));
      }
    },

    // 初始化手势缩放
    getData() {
      let that = this;
      let pic = this.$refs.pdfContainer;
      this.af = new AlloyFinger(pic, {
        pinch(evt) {
          // 避免误操作,过小过滤掉
          let zoom = evt.zoom || 1;
          if (zoom > 0.8 && zoom < 1.2) return false;
          // 防抖
          if (!that.scaleFlag) return false;
          console.log(evt.zoom, '实现缩放');
          that.scaleFlag = false;
          setTimeout(() => {
            that.scaleFlag = true;
          }, 200);
          if (zoom > 1) {
            // 设置最大缩放
            that.scale = that.scale + 0.1 < 1 ? that.scale + 0.1 : 1;
          } else if (zoom < 1) {
            // 设置最小缩放
            that.scale = that.scale - 0.1 > that.oldscale ? that.scale - 0.1 : that.oldscale;
          }
        },
      });
    },
  },
};
</script>

<style lang="less" scoped>
.pdf_box {
  width: 100%;
  height: calc(100vh - 44px);
  overflow-y: scroll;
}
.overlay_dialog {
  position: fixed;
  top: 44px;
  left: 0;
  bottom: 77px;
  z-index: 1;
  width: 100%;
}
/deep/.van-loading {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}
</style>


posted @ 2022-10-25 17:37  sk-xm  阅读(977)  评论(0编辑  收藏  举报