ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

vue3.0使用pdfjs-dist查看pdf文件

2022-02-23 22:02:58  阅读:470  来源: 互联网

标签:canvas dist height state vue3.0 pdf pdfjs const


文章目录

pdf预览组件

前情:项目要的急,就简单的能看pdf文件,没有其他功能

使用的 pdfjs-dist 版本号:2.5.207

接下来,直接上代码

封装组件

<template>
  <template v-for="item in pageNum" :key="item">
    <canvas :id="`pdf-canvas-${item}`" class="pdf-page" />
  </template>
</template>

<script>
import { reactive, toRefs, nextTick, watchEffect } from 'vue'
import * as pdfjs from 'pdfjs-dist'
import pdfjsWorker from 'pdfjs-dist/build/pdf.worker.entry';
import { Toast } from 'vant'

pdfjs.GlobalWorkerOptions.workerSrc = pdfjsWorker

export default {
  name: 'PdfViewer',
  props: {
    url: {type: String, default: ''} // pdf文件路径
  },
  setup (props, { emit }) {
    const state = reactive({
      pageNum: 0,
      pdfCtx: null
    })

    const resolvePdf = (url) => {
      const loadingTask = pdfjs.getDocument(url)
      loadingTask.promise.then(pdf => {
        state.pdfCtx = pdf
        state.pageNum = pdf.numPages
        nextTick(() => {
          renderPdf()
        })
      })
    }

    const renderPdf = (num = 1) => {
      state.pdfCtx.getPage(num).then(page => {
        const canvas = document.getElementById(`pdf-canvas-${num}`)
        const ctx = canvas.getContext('2d')
        const viewport = page.getViewport({ scale: 1 })
        // 画布大小,默认值是width:300px,height:150px
        canvas.height = viewport.height
        canvas.width = viewport.width
        // 画布的dom大小, 设置移动端,宽度设置铺满整个屏幕
        const clientWidth = document.body.clientWidth
        canvas.style.width = clientWidth + 'px'
        // 根据pdf每页的宽高比例设置canvas的高度
        canvas.style.height = clientWidth * (viewport.height / viewport.width) + 'px'
        page.render({
          canvasContext: ctx,
          viewport
        })
        if (num < state.pageNum) {
          renderPdf(num + 1)
        } else {
          emit('onRendered')
		  Toast.clear(); // 取消加载loading
        }
      })
    }

    watchEffect(() => {
      if (props.url) {
      	// 展示加载loading
        Toast.loading({
          message: '加载中...',
          overlay: true,
          forbidClick: true,
          duration: 0,
        });

        resolvePdf(props.url)
      }
    })
    return {
      ...toRefs(state)
    }
  }
}
</script>

组件注册

这里是全局注册组件,main.js中添加下面代码 引入组件

详细方法可看我的文章vue3.0全局注册自定义组件及使用

import PdfViewer from "./components/PdfViewer.vue"

app.component('PdfViewer', PdfViewer)

使用

pdfUrl中传入pdf文件地址

<PdfViewer :url="pdfUrl"></PdfViewer>

参考文章
https://www.52pojie.cn/thread-1391808-1-1.html


增加缩放功能(2021-12-15更新)

有了些空闲时间,想完善下pdf预览组件
看了网上的文章,都需要时间慢慢研究下
空闲时间不多,我就先用我想到的方法,实现下功能叭~

增加了工具栏,有页面缩放功能,和当前页页码展示

缩放功能关键点:
pdfjs的scale设置为需要放大的最大值;
使用css进行缩放

组件

<template>
  <!-- 自由发挥想象的工具栏 -->
  <div class="tool-bar" v-show="totalPageNum != 0">
  	<div class="pageNum">{{currentPageNum}} / {{totalPageNum}}页</div>
    <span class="txt">放大</span>
    <div class="box">
      <div class="mask" v-show="zoom == maxZoom"></div>
      <van-icon name="plus" size="18" @click="zoomChange('plus')"/>
    </div>
    <span class="txt">缩小</span>
    <div class="box">
      <div class="mask" v-show="zoom == minZoom"></div>
      <van-icon name="minus" size="18" @click="zoomChange('minus')"/>
    </div>
  </div>
  <!-- 工具栏 end -->

  <div class="pdf-viewer" @scroll="onScroll">
    <template v-for="item in totalPageNum" :key="item">
      <canvas class="pdf-item" :id="`pdf-canvas-${item}`" :style="{zoom: zoom/10}" />
    </template>
  </div>
</template>

<script>
import { reactive, toRefs, nextTick, watchEffect } from 'vue'
import * as pdfjs from 'pdfjs-dist'
// import {GlobalWorkerOptions, getDocument} from 'pdfjs-dist'
import pdfjsWorker from 'pdfjs-dist/build/pdf.worker.entry';
import { Toast } from 'vant'

pdfjs.GlobalWorkerOptions.workerSrc = pdfjsWorker

export default {
  name: 'PdfViewer',
  props: {
    url: {type: String, default: ''} // pdf文件路径
  },
  setup (props, { emit }) {
    const state = reactive({
      pdfCtx: null,

      currentPageNum: 0, // 当前页
      totalPageNum: 0,
      zoom: 10, // 目前暂时采用css方式缩放页面
      minZoom: 10, // 缩放最小值 一倍
      maxZoom: 50, // 缩放最大值 五倍
    })

    const resolvePdf = (url) => {
      const loadingTask = pdfjs.getDocument(url)
      loadingTask.promise.then(pdf => {
        state.pdfCtx = pdf
        state.totalPageNum = pdf.numPages
        state.currentPageNum = 1

        // 动态计算scale
        pdf.getPage(1).then(res => {
          let boxWidth = document.body.clientWidth - 20
          const [x1, , x2] = res._pageInfo.view;
          const pageWidth = x2 - x1;
          state.scale = boxWidth*(state.maxZoom/10) / pageWidth
        })
        nextTick(() => {
          renderPdf()
        })
      })
    }

    const renderPdf = (num = 1) => {
      state.pdfCtx.getPage(num).then(page => {
        const canvas = document.getElementById(`pdf-canvas-${num}`)
        const ctx = canvas.getContext('2d')
        const viewport = page.getViewport({ scale: state.scale })
        // 画布大小,默认值是width:300px,height:150px
        canvas.width = viewport.width
        canvas.height = viewport.height
        // 画布的dom大小, 设置移动端,宽度设置铺满整个屏幕
        const clientWidth = document.body.clientWidth - 20
        canvas.style.width = clientWidth + 'px'
        // 根据pdf每页的宽高比例设置canvas的高度
        canvas.style.height = clientWidth * (viewport.height / viewport.width) + 'px'
        page.render({
          canvasContext: ctx,
          viewport
        })
        if (num < state.totalPageNum) {
          renderPdf(num + 1)
        } else {
          emit('onRendered')
		      Toast.clear();
        }
      })
    }

	const zoomChange = (value) => {
      state.zoom = value == 'plus' ? state.zoom + 5 : state.zoom - 5

      let pdfViewer = document.getElementsByClassName('pdf-viewer')[0]
      let pages = document.getElementsByClassName('pdf-item')
      pdfViewer.scrollTop = pages[state.currentPageNum-1].offsetTop*state.zoom/10
    }

    const onScroll = (e) => {
      let pages = document.getElementsByClassName('pdf-item')
      for (let i=0; i<state.totalPageNum; i++) {
        let offset = e.target.offsetHeight/2-100 // 距顶部的距离(当前页在滚动到页面可视区的哪个位置时更改currentPageNum)
        if (e.target.scrollTop >= pages[i].offsetTop*state.zoom/10 - offset ) {
          if ((pages[i+1] && e.target.scrollTop < pages[i+1].offsetTop*state.zoom/10 - offset) || !pages[i+1]) {
            state.currentPageNum = i+1 
          }
        }
      }
    }

    watchEffect(() => {
      if (props.url) {
        Toast.loading({
          message: '文件加载中...',
          overlay: true,
          forbidClick: true,
          duration: 0,
        });

        resolvePdf(props.url)
      }
    })
    return {
      ...toRefs(state),
      zoomChange,
      onScroll
    }
  }
}
</script>

<style lang="less" scoped>
  .pdf-viewer {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    padding: 10px 10px 50px;
    overflow: scroll;
    background-color: #f5f5f5;
  }
  // 放飞自我的工具栏
  .tool-bar {
    z-index: 2;
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    height: 45px;
    line-height: 45px;
    color: #fff;
    padding: 0 20px;
    background-color: rgba(85, 85, 85, 0.6);
    display: flex;
    justify-content: flex-end;
    .pageNum {
      flex: 1;
      font-size: 17px;
    }
    .txt {
      font-size: 16px;
      padding-right: 5px;
      margin-left: 20px;
    }
    .box {
      position: relative;
      margin-top: 5px;
      width: 35px;
      height: 35px;
      line-height: 35px;
      text-align: center;
      background-color: #3476FE;
      border-radius: 50%;
      .van-icon {
        vertical-align: middle;
        font-weight: bold;
      }
      .mask {
        z-index: 1;
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background-color: rgba(109, 109, 109, .7);
        border-radius: 50%;
      }
    }
    // 工具栏 end
  }
</style>

使用

父级要有一个整屏高的外层

<div style="position: relative;min-height: calc( 100vh - 50px);">
...
	<PdfViewer :url="pdfUrl"></PdfViewer>
...
</div>

标签:canvas,dist,height,state,vue3.0,pdf,pdfjs,const
来源: https://blog.csdn.net/geejkse_seff/article/details/123100456

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有