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>

运行效果:

相关推荐
℘团子এ9 分钟前
vue3中如何上传文件到腾讯云的桶(cosbrowser)
前端·javascript·腾讯云
学习前端的小z15 分钟前
【前端】深入理解 JavaScript 逻辑运算符的优先级与短路求值机制
开发语言·前端·javascript
星星会笑滴18 分钟前
vue+node+Express+xlsx+emements-plus实现导入excel,并且将数据保存到数据库
vue.js·excel·express
前端百草阁38 分钟前
【TS简单上手,快速入门教程】————适合零基础
javascript·typescript
彭世瑜38 分钟前
ts: TypeScript跳过检查/忽略类型检查
前端·javascript·typescript
Backstroke fish40 分钟前
Token刷新机制
前端·javascript·vue.js·typescript·vue
zwjapple40 分钟前
typescript里面正则的使用
开发语言·javascript·正则表达式
小五Five41 分钟前
TypeScript项目中Axios的封装
开发语言·前端·javascript
临枫54142 分钟前
Nuxt3封装网络请求 useFetch & $fetch
前端·javascript·vue.js·typescript
RAY_CHEN.42 分钟前
vue3 pinia 中actions修改状态不生效
vue.js·typescript·npm