需求: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>
运行效果: