Browse Source

增加翻页动画

fwinfo 3 months ago
parent
commit
e827755421
1 changed files with 326 additions and 0 deletions
  1. 326 0
      src/components/pdf2.vue

+ 326 - 0
src/components/pdf2.vue

@@ -0,0 +1,326 @@
+<template>
+  <div class="pdf">
+    <div class="btnbox">
+      <el-button type="primary" class="el-icon-tickets" size="mini" @click="outlineShow = !outlineShow"></el-button>
+      <!-- <el-button type="primary" v-if="mode == 'pc'" class="el-icon-arrow-left left" size="mini" @click="pre_page"></el-button>
+      <el-button type="primary" v-if="mode == 'pc'" class="el-icon-arrow-right right" size="mini" @click="next_page"></el-button> -->
+      <el-button type="primary" v-if="mode == 'pc'" class="el-icon-plus" size="mini" @click="zoom_big"></el-button>
+      <el-button type="primary" v-if="mode == 'pc'" class="el-icon-minus" size="mini" @click="zoom_small"></el-button>
+    </div>
+    <outline v-if="outlineShow" @outline_item="outline_item" :outlineData="outlineData" class="outline" :style="{ width: outlineWidth }"></outline>
+    <div class="canvasBox">
+      <!-- <canvas v-for="page in pdf_pages" :id="'the-canvas'+page" :key="page" class="canvas"></canvas> -->
+      <canvas @mousewheel="mouseWheel" class="canvas" :id="'the-canvas'"></canvas>
+    </div>
+  </div>
+</template>
+
+<script>
+// pdfjs-dist版本为2.2.228
+import PDFJS from 'pdfjs-dist'
+// 目录
+import outline from './outline.vue'
+// 时间处理
+import moment from 'moment'
+export default {
+  name: 'pdflib',
+  components: {
+    outline
+  },
+  props: {
+    pdf_src: { type: String, default: '' }
+  },
+  data () {
+    return {
+      mode: 'phone',
+      flg: false,
+      // pdf放大系数
+      pdf_scale: 1,
+      // 所有页
+      pdf_pages: [],
+      // 当前页
+      is_page: 1,
+      pdfDoc: null,
+      // 目录大纲
+      outlineData: [],
+      // 目录宽度
+      outlineWidth: '100%',
+      // 是否显示目录
+      outlineShow: false,
+      // 记录当前时间
+      date: 0,
+      // 默认阻断阈值 毫秒
+      threshold: 200,
+      // 目录默认点击后打开或关闭
+      showAndHided: false
+    }
+  },
+  mounted () {
+    this.init()
+    this.fingerInit()
+  },
+  methods: {
+    // 初始化屏幕触控
+    fingerInit () {
+      this.$finger(document.getElementsByTagName('canvas')[0], {
+        pinch: this.zoom,
+        swipe: this.swipeHandler
+      })
+    },
+    // 初始化应用 判断屏幕宽度
+    init () {
+      const result = window.matchMedia('(min-width: 500px)').matches
+      if (result) {
+        this.pdf_scale = 0.3
+        this.outlineWidth = '25%'
+        this.showAndHided = true
+        this.mode = 'pc'
+      }
+      this._loadFile(this.pdf_src)
+    },
+    // 初始化pdf 加载pdf文件
+    _loadFile (url) {
+      const loadingTask = PDFJS.getDocument(url)
+      loadingTask.promise
+        .then(async (pdf) => {
+          this.pdfDoc = pdf
+          this.pdf_pages = this.pdfDoc.numPages
+          this.$nextTick(() => {
+            this._renderPage(this.is_page)
+            this.get_contents()
+          })
+          return null
+        })
+        .catch((err) => {
+          console.log(err)
+        })
+    },
+    // 渲染pdf页
+    _renderPage(num) {
+  this.pdfDoc.getPage(num)
+    .then((page) => {
+      const canvas = document.getElementById('the-canvas')
+      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 viewport = page.getViewport({ scale: (screen.availWidth / page.getViewport({ scale: 1 }).width) * this.pdf_scale })
+      const { width, height } = viewport
+      canvas.width = width * ratio
+      canvas.height = height * ratio
+      canvas.style.width = `${width}px`
+      canvas.style.height = `${height}px`
+
+      ctx.setTransform(ratio, 0, 0, ratio, 0, 0)
+      const renderContext = {
+        canvasContext: ctx,
+        viewport: viewport
+      }
+
+      // 添加翻书动画效果
+      const initialScale = 0.1
+      const targetScale = 1.0
+      let currentScale = initialScale
+
+      function animate() {
+        if (currentScale < targetScale) {
+          currentScale += 0.1 // 调整动画速度可以修改这个增量
+          ctx.clearRect(0, 0, canvas.width, canvas.height)
+          ctx.save()
+          ctx.scale(currentScale, 1)
+          page.render(renderContext)
+          ctx.restore()
+          requestAnimationFrame(animate)
+        } else {
+          this.flg = false // 动画结束后可以设置标志位等
+        }
+      }
+
+      animate()
+    })
+},
+    // _renderPage (num) {
+    //   this.pdfDoc.getPage(num)
+    //     .then((page) => {
+    //       // 获取dom元素
+    //       const canvas = document.getElementById('the-canvas')
+    //       // 设置2D渲染
+    //       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 viewport = page.getViewport({ scale: (screen.availWidth / page.getViewport({ scale: 1 }).width) * this.pdf_scale })
+    //       // 设置元素大小
+    //       const { width, height } = viewport
+    //       canvas.width = width * ratio
+    //       canvas.height = height * ratio
+    //       canvas.style.width = `${width}px`
+    //       canvas.style.height = `${height}px`
+    //       // 重绘cavas
+    //       ctx.setTransform(ratio, 0, 0, ratio, 0, 0)
+    //       const renderContext = {
+    //         canvasContext: ctx,
+    //         viewport: viewport
+    //       }
+    //       // 渲染
+    //       page.render(renderContext)
+    //       this.flg = false
+    //     })
+    // },
+    // 获取目录
+    async get_contents () {
+      const Outline = await this.pdfDoc.getOutline()
+      console.log(Outline)
+      this.outlineData = Outline
+    },
+    // 点击目录
+    async outline_item (e) {
+      const r = await this.pdfDoc.getDestination(e.dest)
+      const p = await this.pdfDoc.getPageIndex(r[0])
+      this.is_page = p + 1
+      this._renderPage(this.is_page)
+      this.outlineShow = this.showAndHided
+    },
+    // 上一页
+    pre_page () {
+      if (this.is_page <= 1) return
+      this.is_page--
+      this._renderPage(this.is_page)
+    },
+    // 下一页
+    next_page () {
+      if (this.is_page >= this.pdf_pages) return
+      this.is_page++
+      this._renderPage(this.is_page)
+    },
+    // 放大
+    zoom_big () {
+      this.pdf_scale += 0.1
+      this._renderPage(this.is_page)
+    },
+    // 缩小
+    zoom_small () {
+      this.pdf_scale -= 0.1
+      this._renderPage(this.is_page)
+    },
+    /*
+    /* 以下为移动端触控事件
+    */
+    // 缩放
+    zoom (e) {
+      const prevent = this.prevent(100)
+      if (!prevent) return
+      this.flg = true
+      const { zoom } = e
+      this.pdf_scale = this.pdf_scale * zoom
+      if (this.pdf_scale > 2) this.pdf_scale = 2
+      if (this.pdf_scale < 1) this.pdf_scale = 1
+      this.domScrol()
+      this._renderPage(this.is_page)
+    },
+    // 移动方向翻页
+    swipeHandler (evt) {
+      if (this.flg) return
+      const prevent = this.prevent(200)
+      if (!prevent) return
+      if (this.pdf_scale !== 0.3 && this.pdf_scale !== 1) {
+        this.domScrol()
+        return
+      }
+      if (evt?.direction === 'Up' || evt?.direction === 'Left') this.next_page()
+      if (evt?.direction === 'Down' || evt?.direction === 'Right') this.pre_page()
+    },
+    // 移动端滚动位置
+    domScrol (e) {
+      const el = document.getElementsByClassName('canvasBox')[0]
+      if (e) {
+        el.scrollLeft = 0
+        el.scrollTop = 0
+      }
+      el.scrollLeft -= 0.1
+      el.scrollTop -= 0.1
+    },
+    // pc滚动事件
+    mouseWheel (e) {
+      if (this.pdf_scale.toFixed(1) > 0.3) return
+      const prevent = this.prevent(200)
+      if (!prevent) return
+      if (e.wheelDelta || e.detail) {
+        // 当鼠标滚轮向上滚动时
+        if (e.wheelDelta > 0 || e.detail < 0) {
+          this.pre_page()
+        }
+        // 当鼠标滚轮向下滚动时
+        if (e.wheelDelta < 0 || e.detail > 0) {
+          this.next_page()
+        }
+      }
+    },
+    // 阻断连续调用
+    prevent (num) {
+      const date = moment().valueOf()
+      if (date - this.data < num ?? this.threshold) return false
+      this.data = date
+      return true
+    },
+    // 动画
+    animation () {
+      console.log('动画')
+    }
+  }
+}
+</script>
+
+<style scoped lang="less">
+.pdf {
+  width: 100vw;
+  height: 100vh;
+}
+.canvasBox {
+  width: 100%;
+  height: 100%;
+  overflow: auto;
+  background: #000;
+  display: flex;
+  align-items: center;
+  // justify-content: center;
+}
+.canvas {
+  margin: 0 auto;
+  display: block;
+}
+.btnbox {
+  position: fixed;
+  top: 10px;
+  left: 5%;
+  width: 90%;
+  height: 5vh;
+  .left {
+    margin-left: 40%;
+  }
+  .right {
+    margin-right: 40%;
+  }
+}
+.outline {
+  height: 95vh;
+  top: 5vh;
+  position: fixed;
+  left: 0;
+}
+.outline ::-webkit-scrollbar {
+  width: 0px; /*对垂直流动条有效*/
+  height: 0px; /*对水平流动条有效*/
+}
+</style>