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>

运行效果:

相关推荐
QQ1__8115175151 小时前
Spring boot名城小区物业管理系统信息管理系统源码-SpringBoot后端+Vue前端+MySQL【可直接运行】
前端·vue.js·spring boot
一粒黑子1 小时前
【实战解析】阿里开源 PageAgent:纯前端 GUI Agent,一行JS让网页支持自然语言操控
前端·javascript·开源
IT枫斗者2 小时前
前端部署后如何判断“页面是不是最新”?一套可落地的版本检测方案(适配 Vite/Vue/React/任意 SPA)
前端·javascript·vue.js·react.js·架构·bug
Beginner x_u2 小时前
链表专题:JS 实现原理与高频算法题总结
javascript·算法·链表
我叫汪枫3 小时前
在后台管理系统中,如何递归和选择保留的思路来过滤菜单
开发语言·javascript·node.js·ecmascript
_.Switch3 小时前
东方财富股票数据JS逆向:secids字段和AES加密实战
开发语言·前端·javascript·网络·爬虫·python·ecmascript
软件技术NINI3 小时前
webkit简介及工作流程
开发语言·前端·javascript·udp·ecmascript·webkit·yarn
Brendan_0013 小时前
JavaScript的Stomp.over
开发语言·javascript·ecmascript
念2343 小时前
f5 shape分析
开发语言·javascript·ecmascript
難釋懷3 小时前
Vue混入
前端·javascript·vue.js