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

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

  • 相关阅读:
    LeetCode 42. Trapping Rain Water
    LeetCode 209. Minimum Size Subarray Sum
    LeetCode 50. Pow(x, n)
    LeetCode 80. Remove Duplicates from Sorted Array II
    Window10 激活
    Premiere 关键帧缩放
    AE 「酷酷的藤」特效字幕制作方法
    51Talk第一天 培训系列1
    Premiere 视频转场
    Premiere 暴徒生活Thug Life
  • 原文地址:https://www.cnblogs.com/ziyoublog/p/15502909.html
Copyright © 2011-2022 走看看