1.安装vue-pdf

npm install --save vue-pdf

2.使用

1)不分页(新建pdfNoPage.vue),代码如下

/*
 * @Author: duyan
 * @Date: 2020-09-25 09:11:13
 * @Last Modified by: duyan
 * @Last Modified time: 2020-09-25 10:19:25
 */
<template>
  <div class="pdfNoPage">
    <div v-if="isLoading" class="mask">
      <loading size="24px" vertical>加载中...</loading>
    </div>
    <div class="pdf-box">
      <pdf
        v-for="i in numPages"
        :key="i"
        :src="pdfSrc"
        :page="i"
        @page-loaded="pageLoaded"
      />
    </div>
  </div>
</template>

<script>
import pdf from 'vue-pdf'
import { Loading } from 'vant'
export default {
  metaInfo: {
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=2,user-scalable=yes' }
    ]
  },
  // 名字
  name: 'PdfNoPage',
  // 部件
  components: {
    pdf,
    Loading
  },
  // 静态
  props: {
    pdfSrc: {
      type: String,
      default: ''
    }
  },
  // 数据
  data() {
    return {
      numPages: undefined,
      isLoading: true
    }
  },
  // 属性的结果会被缓存,除非依赖的响应式属性变化才会重新计算。主要当作属性来使用;
  computed: {
  },
  // 对象内部的属性监听,也叫深度监听
  watch: {
  },
  // 请求数据
  created() {
  },
  mounted() {
    this.getNumPages(this.pdfSrc)
  },
  // 方法表示一个具体的操作,主要书写业务逻辑;
  methods: {
    getNumPages(url) {
      var loadingTask = pdf.createLoadingTask(url)
      loadingTask.promise.then(pdf => {
        this.url = loadingTask
        this.numPages = pdf.numPages
      }).catch((err) => {
        console.log(err)
      })
    },
    // 等pdf页数加载完成的时候,隐藏加载框
    pageLoaded(num) {
      if (num === this.numPages) {
        this.isLoading = false
      }
    }
  }
}
</script>

<style scoped lang="scss">

  // 加载框
  .mask {
    width: 100vw;
    height: 100%;
    position: relative;
    .van-loading {
      position: absolute;
      left: 50%;
      top:50%;
      transform: translate(-50%,-50%);
    }
  }
 .pdf-box {
    padding: 10px;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
    max-width: 1024px;
    width: 100%;
    margin: 0 auto;
    overflow-x: hidden;
    height: 100% ;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    font-size: .28rem;
    span {
      width: 100%;
    }
  }
</style>

2).分页(新建pdfPage.vue),代码如下

/*
 * @Author: duyan
 * @Date: 2020-09-25 09:07:29
 * @Last Modified by: duyan
 * @Last Modified time: 2020-09-25 14:19:48
 */
<template>
  <div class="pdfPage">
    <div v-if="isLoading" class="mask">
      <loading size="24px" vertical>加载中...</loading>
    </div>
    <!-- <v-touch style="height: calc(100% - 25px);" tag="div" @swipeleft="onSwipeLeft" @swiperight="onSwipeRight"> -->
    <div
      class="pdf-box"
      @touchstart="touchstart"
      @touchmove="touchmove"
      @touchend="touchend"
    >
      <pdf
        ref="pdf"
        :src="pdfSrc"
        :page="currentPage"
        @num-pages="pageCount=$event"
        @page-loaded="pageLoaded"
        @loaded="loadPdfHandler"
      />
    </div>
    <!-- </v-touch> -->
    <!--页码-->
    <div v-show="fileType === 'pdf'" class="pdf">
      <van-row type="flex" justify="space-between">
        <van-col span="12" style="text-align:center">
          <div class="touch">
            <van-button
              round
              size="mini"
              type="primary"
              :class="{select:idx==0}"
              @touchstart="idx=0"
              @touchend="idx=-1"
              @click="scaleD"
            >
              放大
            </van-button>
            <van-button
              round
              size="mini"
              type="primary"
              :disabled="scale===100?true:false"
              :class="{select:idx==1}"
              @touchstart="idx=1"
              @touchend="idx=-1"
              @click="scaleX"
            >
              缩小

            </van-button>
          </div>
        </van-col>
        <van-col span="12" style="text-align:center">
          <div class="pagesize">
            <!--上一页-->
            <van-button
              round
              size="mini"
              type="info"
              class="turn"
              :disabled="currentPage==1?true:false"
              :class="{grey: currentPage==1}"
              @click="changePdfPage(0)"
            >上页</van-button>
            {{ currentPage }} / {{ pageCount }}
            <!--下一页-->
            <van-button
              round
              size="mini"
              type="info"
              class="turn"
              :disabled="currentPage==pageCount?true:false"
              :class="{grey: currentPage==pageCount}"
              @click="changePdfPage(1)"
            >下页</van-button>
          </div>
        </van-col>
      </van-row>
    </div>
  </div>
</template>

<script>
import pdf from 'vue-pdf' // 引入pdf组件
import { Loading } from 'vant'
export default {
  metaInfo: {
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=2,user-scalable=yes' }
    ]
  },
  // 名字
  name: 'PdfPage',
  // 部件
  components: {
    pdf,
    Loading
  },
  // 静态
  props: {
    pdfSrc: {
      type: String,
      default: ''
    }
  },
  // 数据
  data() {
    return {
      currentPage: 0, // pdf文件页码
      pageCount: 0, // pdf文件总页数
      fileType: 'pdf', // 文件类型
      isLoading: true,
      scale: 100, // 放大系数
      idx: -1,
      touchDistance: 0,
      previousPinchScale: 1,
      startTime: 0,
      startX: null,
      startY: null,
      moveX: null,
      moveY: null,
      eLen: 0
    }
  },
  // 属性的结果会被缓存,除非依赖的响应式属性变化才会重新计算。主要当作属性来使用;
  computed: {
  },
  // 对象内部的属性监听,也叫深度监听
  watch: {
  },
  // 请求数据
  created() {

  },
  mounted() {
    this.loadPdfHandler()
    // 有时PDF文件地址会出现跨域的情况,这里最好处理一下
    this.pdfSrc = pdf.createLoadingTask(this.pdfSrc)
  },
  // 方法表示一个具体的操作,主要书写业务逻辑;
  methods: {
    // 改变PDF页码,val传过来区分上一页下一页的值,0上一页,1下一页
    changePdfPage(val) {
      console.log(val)
      if (val === 0 && this.currentPage > 1) {
        this.currentPage--
        // console.log(this.currentPage)
      }
      if (val === 1 && this.currentPage < this.pageCount) {
        this.currentPage++
        // console.log(this.currentPage)
      }
    },
    // 放大
    scaleD() {
      this.scale += 5
      this.$refs.pdf.$el.style.width = parseInt(this.scale) + '%'
    },

    // 缩小
    scaleX() {
      if (this.scale === 100) {
        return
      }
      this.scale += -5
      this.$refs.pdf.$el.style.width = parseInt(this.scale) + '%'
    },
    // 等pdf页数加载完成的时候,隐藏加载框
    pageLoaded(num) {
      if (num === this.currentPage) {
        this.isLoading = false
      }
    },
    // pdf加载时
    loadPdfHandler(e) {
      this.currentPage = 1 // 加载的时候先加载第一页
    },
    _getDistance(xLen, yLen) {
      return Math.sqrt(xLen * xLen + yLen * yLen)
    },
    touchstart(e) {
      this.startTime = this._getTime()
      this.startX = e.touches[0].pageX
      this.startY = e.touches[0].pageY
      if (e.touches.length > 1) {
        const point1 = e.touches[0]
        const point2 = e.touches[1]
        const xLen = Math.abs(point2.pageX - point1.pageX)
        const yLen = Math.abs(point2.pageY - point1.pageY)
        this.touchDistance = this._getDistance(xLen, yLen)
      }
    },
    touchmove(e) {
      this.moveX = e.touches[0].pageX
      this.moveY = e.touches[0].pageY
      // e.touches.length为手指的个数
      this.eLen = e.touches.length
      if (e.touches.length > 1) {
        const xLen = Math.abs(e.touches[0].pageX - e.touches[1].pageX)
        const yLen = Math.abs(e.touches[0].pageY - e.touches[1].pageY)
        const touchDistance = this._getDistance(xLen, yLen)
        if (this.touchDistance) {
          const pinchScale = touchDistance / this.touchDistance
          this.previousPinchScale = pinchScale
        }
      }
    },
    _getTime() {
      return new Date().getTime()
    },
    touchend(e) {
      // const timestamp = this._getTime()
      if (this.scale === 100 && this.eLen === 1) {
        if (this.moveX !== null && this.moveX - this.startX > 30) {
          if (this.currentPage !== 1) {
            this.changePdfPage(0)
          }
        } else if (this.moveX !== null && this.moveX - this.startX < -30) {
          if (this.currentPage < this.pageCount) {
            this.changePdfPage(1)
          }
        }
      }
      // alert(this.eLen)
      // if (this.moveX !== null && Math.abs(this.moveX - this.startX) > 5 ||
      // this.moveY !== null && Math.abs(this.moveY - this.startY) > 5) {
      //   if (this.eLen >= 2) { // 手指移动的位移要大于10像素并且手指和屏幕的接触时间要短于500毫秒
      //     // alert('双指')
      //     alert(this.previousPinchScale)
      //     // this._renderPage(1, this.previousPinchScale)
      //     this.$refs.pdf.$el.style.width = parseInt(this.previousPinchScale * this.scale) + '%'
      //     this.scale = this.scale * this.previousPinchScale
      //     this.eLen = 0
      //   }
      // }
    },
    onSwipeLeft() {
      debugger
    },
    onSwipeRight() {
      debugger
    }

  }
}
</script>

<style scoped lang="scss">
  // 加载框
  .mask {
    width: 100vw;
    height: 100%;
    position: relative;
    .van-loading {
      position: absolute;
      left: 50%;
      top:50%;
      transform: translate(-50%,-50%);
    }
  }
  .pdfPage{
    height: calc(100% - 25px);
  }
  .pdf-box {
    padding: 10px;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
    max-width: 1024px;
    width: 100%;
    margin: 0 auto;
    overflow-x: auto;
    height: 100% ;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    font-size: .28rem;
    span {
      width: 100%;
    }
  }
  .pagesize{
    text-align: center;
  }
</style>

2).引用
js

import pdfNoPage from '@/views/scan/pdfNoPage'
import pdfPage from '@/views/scan/pdfPage'

html:

<div  style="height:calc(100% - 46px)">
  <pdf-no-page  :pdf-src="pdfSrc" />
 </div>
  <div style="height:calc(100% - 46px)">
      <pdf-page v-if="flag" :pdf-src="pdfSrc" />
    </div>

data:(文件路径,需要放在静态文件或者放在线上如oss等可以直接访问该路径)

pdfSrc: '',

:在做的时候还需要实现手指滚动翻页以及双指放大的功能,一开始用的是vue-toch,使用参考vue-toch但是引用了之后不起作用,后面直接用了js的手势事件来写,翻页和缩放也都实现了,但是在监听手指个数的时候会出问题(应该是几个手指一起的时候,每个手指开始和结束触碰的时间都不一样),所以最终缩放也就没做成。手势事件参考js手势事件

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐