pdf.js预览,手机端自适应展示

参考:https://blog.csdn.net/qq_30604453/article/details/122236006
https://www.cnblogs.com/jiayouba/p/14969611.html
效果图:在这里插入图片描述

<template>
  <div class="pdf-touch-box">
    <div class="scale-btn-box" :style="{ width: '100vw' }">
      <header-bar
        title="预览"
        :pdfUrl="src"
        :pdfDialogUrl="pdfDialogUrl"
        v-on="$listeners"
      ></header-bar>
    </div>

    <div
      v-show="!loading"
      class="pdf-canvas-wrap"
      :style="{ width: viewWidth + 'px', height: viewHeight + 'px' }"
    ></div>
    <p class="pdf-canvas-tips" v-show="loading">正在加载...</p>
  </div>
</template>

<script>
import HeaderBar from '../components/headerBar'

const CSS_UNITS = 150 / 72.0

let userAgent = (typeof navigator !== 'undefined' && navigator.userAgent) || ''
let platform = (typeof navigator !== 'undefined' && navigator.platform) || ''
let maxTouchPoints = (typeof navigator !== 'undefined' && navigator.maxTouchPoints) || 1

let maxCanvasPixels = 16777216
// PDF之外占据的宽度 -18 padding -18减去滚动条宽度(不确定)
let autoWidth = 36

let isAndroid = /Android/.test(userAgent)
let isIOS =
  /\b(iPad|iPhone|iPod)(?=;)/.test(userAgent) || (platform === 'MacIntel' && maxTouchPoints > 1)
;(function checkCanvasSizeLimitation() {
  if (isIOS || isAndroid) {
    maxCanvasPixels = 5242880
    autoWidth -= 18
  }
})()

export default {
  name: 'negotiateCase-mobileTerminal-pdf',
  components: {
    HeaderBar,
  },
  props: {
    pdfDialogUrl: {
      type: String,
      default: '',
    },
  },
  data() {
    return {
      src: '',
      loading: true,
      pdfDoc: null,
      boxEl: null,
      wrapEl: null,
      areaWidth: 0,
      viewWidth: 0,
      viewHeight: 0,
      pixelRatio: 2,
      isFirstTimeRender: true,
      viewport: null,
      canvasEles: [],
      canvasCtxs: [],
      totallPage: 1,
      pageScale: 1, // pdf 适应窗口产生的 scale
      curCanvasCSSWh: null,
      transform: null,
    }
  },
  mounted() {
    this.src = this.$route.params.pdfUrl || this.pdfDialogUrl
    this.init()
  },
  methods: {
    async init() {
      this.boxEl = document.querySelector('.pdf-touch-box')
      this.wrapEl = document.getElementsByClassName('pdf-canvas-wrap')[0]
      this.areaWidth = this.boxEl.clientWidth

      const loadingState = await this.getPDF()
      if (loadingState === 'success') this.initRenderOneByOne()
      else {
        that.loading = false
        this.boxEl.innerText = loadingState
      }
    },

    getPDF() {
      let that = this
      return new Promise(reslove => {
        window.pdfjsLib
          .getDocument({
            url: that.src,
            cMapUrl: 'https://cdn.jsdelivr.net/npm/pdfjs-dist@2.2.228/cmaps/',
            cMapPacked: true,
          })
          .promise.then(
            function (pdfDoc_) {
              that.pdfDoc = pdfDoc_
              that.totallPage = pdfDoc_.numPages
              that.loading = false
              reslove('success')
            },
            function (reason) {
              console.log(reason.message)
              that.loading = false
              reslove(reason.name)
            }
          )
      })
    },

    initRenderOneByOne() {
      for (let pageNum = 1; pageNum <= this.totallPage; pageNum++) {
        let canvas = document.createElement('canvas')
        canvas.setAttribute('id', `pdf-canvas${pageNum}`)
        canvas.setAttribute('class', `pdfcanvas`)
        // alpha 设定 canvas 背景总是不透明,可以加快浏览器绘制透明的内容和图片 初始化出来 canvas 为黑色背景
        // 实际上 导致 重新渲染的时候 闪黑屏
        // let ctx = canvas.getContext("2d", {
        //   alpha: false,
        // });
        let ctx = canvas.getContext('2d')
        this.canvasCtxs.push(ctx)
        this.canvasEles.push(canvas)
        this.wrapEl.appendChild(canvas)
      }
      this.renderSinglePage(this.canvasEles[0], 1)
    },

    renderSinglePage(canvas, pageNum) {
      let ctx = this.canvasCtxs[pageNum - 1]
      let that = this

      this.pdfDoc.getPage(pageNum).then(function (page) {
        if (that.isFirstTimeRender) that.initView(page, ctx)

        if (pageNum === 1) that.getCanvasCSSWH()

        canvas.width = that.curCanvasCSSWh.width
        canvas.height = that.curCanvasCSSWh.height
        canvas.style.width = that.curCanvasCSSWh.styleWidth + 'px'
        canvas.style.height = that.curCanvasCSSWh.styleHeight + 'px'
        canvas.style['border'] = '#d6d6d6 solid 1px'
        canvas.style.margin = '9px 0 0 0'

        let renderContext = {
          canvasContext: ctx,
          transform: that.transform,
          viewport: that.viewport,
          enableWebGL: false,
          renderInteractiveForms: false,
        }
        let renderTask = page.render(renderContext)

        renderTask.promise.then(function () {
          if (that.totallPage >= ++pageNum) {
            that.renderSinglePage(that.canvasEles[pageNum - 1], pageNum)
          }
        })
      })
    },
    getCanvasCSSWH() {
      let outputScale = {
        sx: this.pixelRatio,
        sy: this.pixelRatio,
        scaled: this.pixelRatio !== 1,
      }

      let pixelsInViewport = this.viewport.width * this.viewport.height
      let maxScale = Math.sqrt(maxCanvasPixels / pixelsInViewport)

      if (outputScale.sx > maxScale || outputScale.sy > maxScale) {
        outputScale.sx = maxScale
        outputScale.sy = maxScale
        outputScale.scaled = true
      }

      let sfx = (0, this.approximateFraction)(outputScale.sx)
      let sfy = (0, this.approximateFraction)(outputScale.sy)
      const width = (0, this.roundToDivide)(this.viewport.width * outputScale.sx, sfx[0])
      const height = (0, this.roundToDivide)(this.viewport.height * outputScale.sy, sfy[0])
      const styleWidth = (0, this.roundToDivide)(this.viewport.width, sfx[1])
      const styleHeight = (0, this.roundToDivide)(this.viewport.height, sfy[1])

      if (this.pixelRatio !== 1) this.transform = [this.pixelRatio, 0, 0, this.pixelRatio, 0, 0]

      this.viewWidth = styleWidth + 2
      // 12 加上 canvas border margin 误差?2 + 9 + 1
      this.viewHeight = this.totallPage * (this.viewport.height + 12) + 9

      this.curCanvasCSSWh = { width, height, styleWidth, styleHeight }
      return this.curCanvasCSSWh
    },
    approximateFraction(x) {
      if (Math.floor(x) === x) {
        return [x, 1]
      }

      var xinv = 1 / x
      var limit = 8

      if (xinv > limit) {
        return [1, limit]
      } else if (Math.floor(xinv) === xinv) {
        return [1, xinv]
      }

      var x_ = x > 1 ? xinv : x
      var a = 0,
        b = 1,
        c = 1,
        d = 1

      while (q < limit) {
        var p = a + c,
          q = b + d

        if (q > limit) {
          break
        }

        if (x_ <= p / q) {
          c = p
          d = q
        } else {
          a = p
          b = q
        }
      }

      var result

      if (x_ - a / b < c / d - x_) {
        result = x_ === x ? [a, b] : [b, a]
      } else {
        result = x_ === x ? [c, d] : [d, c]
      }

      return result
    },
    roundToDivide(x, div) {
      var r = x % div
      return r === 0 ? x : Math.round(x - r + div)
    },

    initView(page, ctx) {
      let devicePixelRatio = window.devicePixelRatio || 1
      let backingStoreRatio =
        ctx.webkitBackingStorePixelRatio ||
        ctx.mozBackingStorePixelRatio ||
        ctx.msBackingStorePixelRatio ||
        ctx.oBackingStorePixelRatio ||
        ctx.backingStorePixelRatio ||
        1
      this.pixelRatio = devicePixelRatio / backingStoreRatio

      this.viewport = page.getViewport({
        scale: CSS_UNITS,
      })

      this.pageScale = (this.areaWidth - autoWidth) / this.viewport.width
      let curViewport = page.getViewport({
        scale: this.pageScale * CSS_UNITS,
      })
      this.viewport = curViewport

      this.isFirstTimeRender = false
    },
  },
}
</script>

<style scoped>
.pdf-touch-box {
  padding: 9px;
  width: calc(100% - 18px);
  height: calc(100% - 18px);
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.scale-btn-box {
  position: fixed;
  top: 0;
  left: 0;
  height: 44px;
}
.pdf-canvas-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  overflow-y: auto;
  overflow-x: hidden;
  margin-top: 44px;
  padding-top: 9px;
}
.pdf-canvas-tips {
  margin-top: 44px;
}
</style>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值