zoukankan      html  css  js  c++  java
  • nuxt使用pdfjs-dist插件实现pdf预览

    首先声明一下,pdfjs-dist要是版本安装不对,会出现各种各样的bug!!!

    目前我项目中pdfjs-dist的版本和nuxt的版本:

    "nuxt": "^2.15.8",
    "pdfjs-dist": "2.3.200",

    我项目中版本错误遇到的错误:PDF.js报错workerSrc修复

    一、项目背景

    因为公司的项目中要做合同签订的功能,需要涉及到用户预览合同的功能,因此我的痛苦就到来了o(╥﹏╥)o

    这个功能最初讨论之后是由后端返回pdf的链接,前端同学实现pdf在线预览的效果,效果图如下:

     二、功能实现

    最初我在网上经过查找决定使用vue-pdf的插件来实现pdf预览的功能,在本地开发中实现了功能,发布到测试环境也运行正常。

    最最让人担心的事情还是发生了,发布到正式环境之后整个项目都报错了。我真是吐血了。。。。

    Uncaught DOMException: Failed to construct 'Worker': 
    Script at 'http://a.com/ef3086d432cfbec65966.worker.js' 
    cannot be accessed from origin 'http:/b.com'.

    经过一番查找终于找到了具体原因,是因为vue-pdf里面为了加快pdf的渲染使用了Worker ,因为我们项目在正式环境当中静态文件之类的是放在七牛上面的,然而worker 是不能跨域的,将页面和静态资源分开的场景,就会出现跨域问题。--解决 vue-pdf 打包后跨域报错Web Workers 资源跨域问题

    三、解决方案

    node_modules/vue-pdf/src/vuePdfNoSss.vue 中,有一个 Worker 支持的判断,一般的vue项目当中可以直接注释掉重新打包就可以了。

    // 注释if内的两句代码或者注释整个if语句
    if ( typeof window !== 'undefined' && 'Worker' in window && navigator.appVersion.indexOf('MSIE 10') === -1 ) {
      // var PdfjsWorker = require('worker-loader!pdfjs-dist/build/pdf.worker.js');
      // PDFJS.GlobalWorkerOptions.workerPort = new PdfjsWorker();
    }

    注释掉上面的代码,就不走 web worker 了,页面能够正常运行了;相对的,页面加载时间可能会变长,性能可能会降低;

    注意:因为我的项目使用了自动化部署,每次部署的时候都会重新npm i拉取新的包,这样的话我在本地修改vue-pdf的文件就不行了

    基于以上原因,我只能更换插件重新寻找合适的插件。经过一番查找更换为pdfjs-dist插件,具体实现:

    <template>
      <div class="pdf-preview-container">
        <div
          v-for="page in docPages"
          :key="page"
          ref="container"
          class="page-container"
          :style="{
            height: `${pageHeight}px`,
          }"
        >
          <canvas v-if="renderList.includes(page)"> </canvas>
        </div>
      </div>
    </template>
    
    <script>
    export default {
      props: {
        url: {
          type: String,
          required: true,
        },
        renderPages: {
          type: Number,
          default: 5,
        },
        customScroll: {
          type: Boolean,
          default: false,
        },
        offsetHeight: {
          type: Number,
          default: 0,
        },
      },
      data() {
        return {
          doc: null,
          docPages: 0,
          currentPage: 0,
          pageHeight: 0,
          renderList: [],
        }
      },
      watch: {
        url: {
          immediate: true,
          handler() {
            this.getPDFFile()
          },
        },
      },
      mounted() {
        if (!this.customScroll) {
          document.addEventListener('scroll', this.scroll)
        }
      },
      beforeDestroy() {
        document.removeEventListener('scroll', this.scroll)
      },
      methods: {
        getPDFFile() {
          if (!this.url) return
          this.currentPage = 0
          const pdfJS = require('pdfjs-dist/build/pdf')
          const pdfjsWorker = require('pdfjs-dist/build/pdf.worker.entry')
          pdfJS.GlobalWorkerOptions.workerSrc = pdfjsWorker
          pdfJS.getDocument(this.url).then(pdf => {
            // console.log('pdf: ', pdf)
            this.doc = pdf
            this.docPages = pdf._pdfInfo.numPages
            this.$nextTick(() => {
              this.docPages && this.scrollToPage(1)
            })
          })
        },
        scrollToPage(pageNo) {
          if (this.currentPage === pageNo) return
          this.currentPage = pageNo
          let list = []
          for (
            let page = pageNo - this.renderPages;
            page <= pageNo + this.renderPages;
            page++
          ) {
            list.push(page)
          }
          list = list.filter(page => page <= this.docPages && page >= 1)
          this.$nextTick(() => {
            this.renderList = list
            this.renderList.forEach(page => {
              this.renderPage(page)
            })
          })
        },
        // 渲染page
        renderPage(pageNo) {
          this.doc.getPage(pageNo).then(page => {
            // console.log('page: ', page)
            const container = this.$refs.container[pageNo - 1]
            if (!container) return
            const canvas = container.querySelector('canvas')
            if (!canvas || canvas.__rendered) return
            const ctx = canvas.getContext('2d')
            const dpr = window.devicePixelRatio || 1
            const bsr =
              ctx.webkitBackingStorePixelRatio ||
              ctx.mozBackingStorePixelRatio ||
              ctx.msBackingStorePixelRatio ||
              ctx.oBackingStorePixelRatio ||
              ctx.backingStorePixelRatio ||
              1
            const ratio = dpr / bsr
            const rect = container.getBoundingClientRect()
            const viewport = page.getViewport(1)
            const width = rect.width
            const height = (width / viewport.width) * viewport.height
            canvas.style.width = `${width}px`
            canvas.style.height = `${height}px`
            this.pageHeight = height
            canvas.height = height * ratio
            canvas.width = width * ratio
            ctx.setTransform(ratio, 0, 0, ratio, 0, 0)
            page.render({
              canvasContext: ctx,
              viewport: page.getViewport(width / viewport.width),
            })
            canvas.__rendered = true
          })
        },
        scroll() {
          this.checkRender(document.documentElement)
        },
        checkRender(el) {
          if (!this.pageHeight) return
          let scrollTop = el.scrollTop
          if (el === document.documentElement) {
            scrollTop =
              el.scrollTop || window.pageYOffset || document.body.scrollTop
          }
          let page = Math.floor((scrollTop - this.offsetHeight) / this.pageHeight)
          page = Math.max(page, 1)
          page = Math.min(page, this.docPages)
          this.scrollToPage(page)
        },
      },
    }
    </script>

    页面上调用:

    <template>
      <div id="app">
        <pdf-preview :url="url"></pdf-preview>
      </div>
    </template>
    
    <script>
    import pdfPreview from "./components/PdfPreview.vue";
    
    export default {
      name: "app",
      components: {
        pdfPreview,
      },
      data() {
        return {
          url: "/static/pdf.pdf",
        };
      },
    };
    </script>

    参考链接:https://github.com/Lushenggang/pdf-preview

    经过一番折腾终于解决了这个问题,真是吐血了。

  • 相关阅读:
    几种简单排序算法
    【转】虚拟机下CentOS7开启SSH连接
    【转】SignalR来做实时Web聊天
    加密算法(DES,AES,RSA,MD5,SHA1,Base64)比较和项目应用
    C#加密解密(DES,AES,Base64,md5,SHA256,RSA,RC4)
    【C#公共帮助类】给大家分享一些加密算法 (DES、HashCode、RSA、AES等)
    对称加密与非对称加密
    PowerDesigner概念模型与物理模型相互转换及导出数据字典
    SQO2008配置管理工具服务显示远程过程调用失败
    MongoDB学习笔记-数据格式及数据类型
  • 原文地址:https://www.cnblogs.com/ziyoublog/p/15502909.html
Copyright © 2011-2022 走看看