vue-pdf使用填坑之旅

1,011 阅读2分钟

基础介绍

     DF文件在线预览的功能相信大家都是有遇到过的, 但在我平时的项目中, 公司提供了相应的插件, 但是在h5等其他项目中, 我们还是只能靠自己呀! 今天就大概说一下 vue-pdf 这个组件, 大部分的需求还是可以满足的。

       vue-pdf实现pdf文件在线预览。

预览各方案对比

  • 如果只想简单在页面中嵌套 PDF,使用 iframe / object / embed 是最好的选择,它不需要你自己去编写翻页组件、不需要去调整样式,用户体验佳

  • 如果对样式没有定制化的需求,使用 vueshowpdf 也是非常不错,弹窗式的 UI 看起来会更加高大上。

  • 如果对权限控制、样式定制需求较高,使用 vue-pdf 是最好的选择,接口和属性较全,扩展能力强,自由度高。

填坑

使用vue-pdf打包生成***.worker.js,在使用cdn后跨域问题

方案一

步骤一:修改node_modules中的worker-loader/dist/workers/index.js

将publicPath 改为./

步骤二: 添加依赖patch-package,修改package.json

cnpm i patch-package --save-dev
在package.json中的scripts中添加 "postinstall": "patch-package"

步骤三:执行命令:npx patch-package worker-loader

执行完成后项目更目录会生成patches的目录,里面有一个补丁文件

文件中记录修改的内容步骤二与三的功能就是给node_modules打补丁。

步骤四:删除node_modules重新cnpm install,再打包就可以了。

代码提交git后其他人cnpm install后的依赖就是已经修改过的,我们公司使用的阿里云效的自动构建打包,云端构建部署,实测有效。项目运行是可以看到只有这个***.worker.js没有使用代理,功能正常!

方案二、将pdf包复制保存本地

src/components/vue-pdf/vuePdfNoSss.vue 文件

import resizeSensor from 'vue-resize-sensor'

export default function (pdfjsWrapper) {

    var createLoadingTask = pdfjsWrapper.createLoadingTask
    var PDFJSWrapper = pdfjsWrapper.PDFJSWrapper

    return {
        createLoadingTask: createLoadingTask,
        render: function (h) {
            return h(
                'span', {
                    attrs: {
                        style: 'position: relative; display: block',
                    },
                },
        [
          h('canvas', {
                        attrs: {
                            style: 'display: inline-block; width: 100%; height: 100%; vertical-align: top',
                        },
                        ref: 'canvas',
                    }),
          h('span', {
                        style: 'display: inline-block; width: 100%; height: 100%',
                        class: 'annotationLayer',
                        ref: 'annotationLayer',
                    }),
          h(resizeSensor, {
                        props: {
                            initial: true,
                        },
                        on: {
                            resize: this.resize,
                        },
                    }),
        ],
            )
        },
        props: {
            src: {
                type: [String, Object, Uint8Array],
                default: '',
            },
            page: {
                type: Number,
                default: 1,
            },
            rotate: {
                type: Number,
            },
        },
        watch: {
            src: function () {
                this.pdf.loadDocument(this.src)
            },
            page: function () {
                this.pdf.loadPage(this.page, this.rotate)
            },
            rotate: function () {
                this.pdf.renderPage(this.rotate)
            },
        },
        methods: {
            resize: function (size) {
                // check if the element is attached to the dom tree || resizeSensor being destroyed
                if (this.$el.parentNode === null || (size.width === 0 && size.height === 0)) return

                // on IE10- canvas height must be set
                this.$refs.canvas.style.height =
                    this.$refs.canvas.offsetWidth * (this.$refs.canvas.height / this.$refs.canvas.width) + 'px'
                // update the page when the resolution is too poor
                var resolutionScale = this.pdf.getResolutionScale()

                if (resolutionScale < 0.85 || resolutionScale > 1.15) this.pdf.renderPage(this.rotate)

                // this.$refs.annotationLayer.style.transform = 'scale('+resolutionScale+')';
            },
            print: function (dpi, pageList) {
                this.pdf.printPage(dpi, pageList)
            },
        },

        // doc: mounted hook is not called during server-side rendering.
        mounted: function () {
            this.pdf = new PDFJSWrapper(this.$refs.canvas, this.$refs.annotationLayer, this.$emit.bind(this))

            this.$on('loaded', function () {
                this.pdf.loadPage(this.page, this.rotate)
            })

            this.$on('page-size', function (width, height) {
                this.$refs.canvas.style.height = this.$refs.canvas.offsetWidth * (height / width) + 'px'
            })

            this.pdf.loadDocument(this.src)
        },

        // doc: destroyed hook is not called during server-side rendering.
        destroyed: function () {
            this.pdf.destroy()
        },
    }
}

src/components/vue-pdf/vuePdfNoSss.vue  目录

< style src = "./annotationLayer.css" > < /style> 
<script >
 import componentFactory from './componentFactory.js'

let component = componentFactory({})
if (process.env.VUE_ENV !== 'server') {
    var pdfjsWrapper = require('./pdfjsWrapper.js').default
    var PDFJS = require('pdfjs-dist/es5/build/pdf.js')
    const pdfjsWrapper = require('./pdfjsWrapper.js').default
    const PDFJS = require('pdfjs-dist/es5/build/pdf.js')

    if (typeof window !== 'undefined' && 'Worker' in window && navigator.appVersion.indexOf('MSIE 10') === -1) {
        var PdfjsWorker = require('worker-loader?inline=true&fallback=false!pdfjs-dist/build/pdf.worker.js')
        const PdfjsWorker = require('worker-loader?inline=true&fallback=false!pdfjs-dist/build/pdf.worker.js')
        PDFJS.GlobalWorkerOptions.workerPort = new PdfjsWorker()
    }

    var component = componentFactory(pdfjsWrapper(PDFJS))
} else {
    var component = componentFactory({})
    component = componentFactory(pdfjsWrapper(PDFJS))
}

export default component
    </script>

要注意这个地方改动

重新创建组件    src/pages/pdf-viewer/index.vue

<template>
	<div>
		<pdf v-for="i in numPages" :key="i" :src="pdfFile" :page="i" @page-loaded="pageLoaded"></pdf>
	</div>
</template>
<script>
import pdf from '@/components/vue-pdf/src/vuePdfNoSss.vue'
import pdf from '@/components/vue-pdf/vuePdfNoSss.vue'
import { querystrs } from '@/utils/querystrs'

export default {
  name: 'PDFViewer',

  components: {
    pdf,
  },

  data() {
    return {
      pdfUrl: decodeURIComponent(querystrs.pdf),
      pdfFile: null,
      numPages: undefined,
      loadedRatio: 0,
    }
  },

  created() {
    this.pdfFile = pdf.createLoadingTask(this.pdfUrl)
  },

  mounted() {
    this.getPdfFile()
  },

  methods: {
    getPdfFile() {
      Toast.loading()
      this.pdfFile.promise
        .then((pdf) => {
          this.numPages = pdf.numPages
          console.log(pdf)
        })
        .catch(() => {
          Toast.hide()
          window.location.replace(this.pdfUrl)
        })
    },
    pageLoaded(currPage) {
      if (currPage && currPage === this.numPages) {
        Toast.hide()
      }
      return
    },
  },
}
</script>
<style lang="stylus" scoped></style>