vue2 使用pdf.js 实现pdf预览,并可复制文本

需求:pdf预览,并且可以选中pdf的内容进行复制。

在ruoyi的vue前端项目中用到,参考了网上不少文章,因为大部分没给具体的pdf.js版本,导致运行过程中报各种api 错误,经过尝试以下版本可用,故记录一下:

安装依赖:

javascript 复制代码
 npm  install pdfjs-dist@2.0.943

vue 页面

javascript 复制代码
<template>
  <div>
    <button @click="scalBig">放大</button>
    <button @click="scalSmall">缩小</button>
    <p>页码:{{ `${pageNo}/${totals.length}` }}</p>
    <div class="drag-box" id="dragBox" @scroll="scrollfun($event)">
      <el-scrollbar>
        <div class="wrapper" id="pdf-container">
          <div v-for="item in totals" :id="`page-${item}`" :key="item" class="pdf-box">
            <canvas :id="'canvas-pdf-' + item" class="canvas-pdf"></canvas>
          </div>
        </div>
      </el-scrollbar>
    </div>
  </div>
</template>
  
<script>
const PDFJS = require('pdfjs-dist')
PDFJS.GlobalWorkerOptions.workerSrc = require('pdfjs-dist/build/pdf.worker.min')
import { TextLayerBuilder } from 'pdfjs-dist/web/pdf_viewer'
import 'pdfjs-dist/web/pdf_viewer.css'
import axios from 'axios';
export default {
  name: 'showPdf',
  // props: ['pdfUrl'],
  data() {
    return {
      scale: 1.4,
      totals: [],
      pageNo: 1,
      viewHeight: 0,
      pdfUrl: 'http://localhost/a.pdf'
    }
  },
  mounted() {
    this.renderPdf(this.scale)
  },
  watch: {
    scale(val) {
      this.totals = []
      this.renderPdf(val)
    }
  },
  methods: {
    async downloadAndConvertToUint8Array(pdfUrl) {
      // 使用 axios 发送 GET 请求获取 PDF 文件数据
      const response = await axios({
        url: pdfUrl,
        method: 'GET',
        responseType: 'arraybuffer', // 设置响应类型为 arraybuffer
      });

      // 将 arraybuffer 转换为 Uint8Array
      const uint8Array = new Uint8Array(response.data);

      return uint8Array;
    },
    renderPdf(scale) {

      this.downloadAndConvertToUint8Array(this.pdfUrl)
        .then((uint8Array) => {
          console.log(uint8Array);
          // 现在你可以用这个 Uint8Array 对象进行进一步处理,例如传递给PDF.js库渲染PDF
          // 当 PDF 地址为跨域时,pdf 应该已流的形式传输,否则会出现pdf损坏无法展示
          PDFJS.getDocument(uint8Array).then(pdf => {
            // 得到PDF的总的页数
            let totalPage = pdf.numPages
            let idName = 'canvas-pdf-'
            // 根据总的页数创建相同数量的canvas
            this.createCanvas(totalPage, idName)
            for (let i = 1; i <= totalPage; i++) {
              pdf.getPage(i).then((page) => {
                let pageDiv = document.getElementById(`page-${i}`)
                let viewport = page.getViewport(scale)
                let canvas = document.getElementById(idName + i)
                let context = canvas.getContext('2d')
                canvas.height = viewport.height
                canvas.width = viewport.width
                this.viewHeight = viewport.height
                let renderContext = {
                  canvasContext: context,
                  viewport
                }
                // 如果你只是展示pdf而不需要复制pdf内容功能,则可以这样写render
                // page.render(renderContext) 如果你需要复制则像下面那样写利用text-layer
                page.render(renderContext).then(() => {
                  return page.getTextContent()
                }).then((textContent) => {
                  // 创建文本图层div
                  const textLayerDiv = document.createElement('div')
                  textLayerDiv.setAttribute('class', 'textLayer')
                  // 将文本图层div添加至每页pdf的div中
                  pageDiv.appendChild(textLayerDiv)
                  // 创建新的TextLayerBuilder实例
                  let textLayer = new TextLayerBuilder({
                    textLayerDiv: textLayerDiv,
                    pageIndex: page.pageIndex,
                    viewport: viewport
                  })
                  textLayer.setTextContent(textContent)
                  textLayer.render()
                })
              })
            }
          })
        })
        .catch((error) => {
          console.error('Error downloading or converting the PDF:', error);
        });


    },
    createCanvas(totalPages) {
      for (let i = 1; i <= totalPages; i++) {
        this.totals.push(i)
      }
    },
    // 分页
    scrollfun(e) {
      let scrollTop = e.target.scrollTop
      if (scrollTop === 0) {
        this.pageNo = 1
      } else {
        this.pageNo = Math.ceil(scrollTop / this.viewHeight)
      }
    },
    // 放大
    scalBig() {
      this.scale = this.scale + 0.1
    },
    // 缩小
    scalSmall() {
      if (this.scale > 1.2) {
        this.scale = this.scale - 0.1
      }
    }
  }
}
</script>
  
<style scoped lang="scss">
.drag-box {
  height: 800px;
}

.pdf-box {
  position: relative;
}

.el-scrollbar__wrap {
  overflow-x: hidden;
}
</style>

运行效果:

相关推荐
Cachel wood几秒前
python round四舍五入和decimal库精确四舍五入
java·linux·前端·数据库·vue.js·python·前端框架
joan_856 分钟前
layui表格templet图片渲染--模板字符串和字符串拼接
前端·javascript·layui
还是大剑师兰特29 分钟前
什么是尾调用,使用尾调用有什么好处?
javascript·大剑师·尾调用
Watermelo6171 小时前
详解js柯里化原理及用法,探究柯里化在Redux Selector 的场景模拟、构建复杂的数据流管道、优化深度嵌套函数中的精妙应用
开发语言·前端·javascript·算法·数据挖掘·数据分析·ecmascript
LostSpeed2 小时前
在福昕(pdf)阅读器中导航到上次阅读页面的方法
pdf
旭久2 小时前
SpringBoot的Thymeleaf做一个可自定义合并td的pdf表格
pdf·html·springboot
一个处女座的程序猿O(∩_∩)O3 小时前
小型 Vue 项目,该不该用 Pinia 、Vuex呢?
前端·javascript·vue.js
燃先生._.9 小时前
Day-03 Vue(生命周期、生命周期钩子八个函数、工程化开发和脚手架、组件化开发、根组件、局部注册和全局注册的步骤)
前端·javascript·vue.js
高山我梦口香糖10 小时前
[react]searchParams转普通对象
开发语言·前端·javascript