在vue项目中使用pdf-dist在线预览PDF

1,658 阅读1分钟

项目中需要查看PDF文件,依次使用了vue-pdf、pdf-dist,发现最好用的是下面链接的解决方案,基于pdf-dist的一种方案。

github.com/Lushenggang…

1、安装pdf-dist

npm install pdf-dist --save

2、新建一个pdfPreview.vue文件

<template>
  <div class="container">
    <div
      v-for="page in pages"
      :key="page"
      ref="pageContainer"
      :style="{
        borderBottom: '1px solid #DFDFDF',
        height: pageHeight + 'px'
      }">
      <canvas v-if="renderList.includes(page)"></canvas>
    </div>
  </div>
</template>

<script>
import pdfJS from 'pdfjs-dist'
export default {
  props: {
    url: {
      type: String,
      required: true
    },
    manualRender: {
      type: Boolean,
      default: false
    },
    renderPages: { // 前后各预渲染多少页
      type: Number,
      default: 5
    },
    showPageLine: {
      type: Boolean,
      default: true
    }
  },
  data () {
    return {
      pdfDoc: null,
      pages: 0,
      currentPage: 0,
      pageHeight: 0,
      renderList: [], // 渲染的页码数组
      timerIndex: 0
    }
  },
  watch: {
    url () {
      this.getPDFFile()
    }
  },
  created () {
    this.getPDFFile()
    if (!this.manualRender) {
      document.addEventListener('scroll', this.documentScroll)
    }
  },
  beforeDestroy () {
    document.removeEventListener('scroll', this.documentScroll)
    this.timerIndex && clearTimeout(this.timerIndex)
  },
  methods: {
    getPDFFile () {
      if (!this.url) return
      pdfJS.getDocument(this.url).then(pdf => {
        this.pdfDoc = pdf
        this.pages = this.pdfDoc.numPages
        this.$nextTick(() => {
          this.pages && 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)
      }
      for (let idx = list.length; idx >= 0; idx--) {
        if (list[idx] > this.pages || list[idx] < 1) list.splice(idx, 1)
      }
      this.$nextTick(() => {
        this.renderList = list
        this.renderList.forEach(page => {
          this.renderPage(page)
        })
      })
    },
    renderPage (pageNo) {
      this.pdfDoc.getPage(pageNo).then(page => {
        let containerNode = this.$refs.pageContainer[pageNo - 1]
        if (!containerNode) return
        let canvas = containerNode.querySelector('canvas')
        if (!canvas || canvas.__rendered) return
        let ctx = canvas.getContext('2d')
        let dpr = window.devicePixelRatio || 1
        let bsr = ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1
        let ratio = dpr / bsr
        let viewport = page.getViewport(screen.availWidth / page.getViewport(.5).width)
        canvas.width = viewport.width * ratio
        canvas.height = viewport.height * ratio
        canvas.style.width = viewport.width + 'px'
        canvas.style.height = viewport.height + 'px'
        this.pageHeight = viewport.height
        ctx.setTransform(ratio, 0, 0, ratio, 0, 0)
        let renderCtx = {
          canvasContext: ctx,
          viewport
        }
        page.render(renderCtx)
        canvas.__rendered = true
      })
    },
    documentScroll () {
      this.checkRender()
    },
    checkRender () {
      this.timerIndex && clearTimeout(this.timerIndex)
      this.timerIndex = setTimeout(this.renderCurrent, 100)
    },
    renderCurrent () {
      this.$nextTick(() => {
        if (this.pages <= 0) return
        if (!this.pageHeight) return
        if (!this.$refs.pageContainer[0]) return
        let rect = this.$refs.pageContainer[0].getBoundingClientRect()
        if (rect.top >= 0) {
          this.scrollToPage(1)
        } else {
          let page = Math.floor(-rect.top / this.pageHeight) + 1
          if (page > this.pages) page = this.pages
          this.scrollToPage(page)
        }
      })
    }
  }
}
</script>

3、项目中直接引用组件,搞定

import pdfPreview from './components/PdfPreview.vue'

<pdf-preview :url="url"></pdf-preview>

个人的微信公众号:小Jerry有话说,平时会发一些技术文章和读书笔记,欢迎交流。

微信图片_20200325182734.jpg