赞
踩
其他方法实现:vue3中使用 vue-pdf-embed 实现pdf文件预览、翻页、下载等功能
pdfjs-dist
,此处指定版本为 2.16.105
yarn add pdfjs-dist@2.16.105
注:3.x版本部分功能的实现方法与旧版本存在差异。
html
结构内容<template>
<div id="pdf-view">
<canvas v-for="page in state.pdfPages" :key="page" id="pdfCanvas" />
<div id="text-view"></div>
</div>
</template>
js
功能实现:<script setup> import * as pdfjsViewer from 'pdfjs-dist/web/pdf_viewer.js' import 'pdfjs-dist/web/pdf_viewer.css' import * as PDF from 'pdfjs-dist' // 文件路径 import pdf from './2020试卷.pdf'; import { ref, reactive, onMounted, nextTick } from 'vue'; const state = reactive({ // 文件路径 pdfPath: pdf, // 总页数 pdfPages: 1, // 页面缩放 pdfScale: 2, }) onMounted(() => { loadFile(state.pdfPath) }); let pdfDoc = null; function loadFile(url) { PDF.getDocument({ url, cMapUrl: 'https://cdn.jsdelivr.net/npm/pdfjs-dist@2.16.105/cmaps/', cMapPacked: true, }).promise.then((pdf) => { pdfDoc = pdf // 获取pdf文件总页数 state.pdfPages = pdf.numPages nextTick(() => { renderPage(1) // 从第一页开始渲染 }) }) } function renderPage(num) { pdfDoc.getPage(num).then((page) => { const canvas = document.getElementById('pdfCanvas') const ctx = canvas.getContext('2d') const viewport = page.getViewport({ scale: state.pdfScale }) canvas.width = viewport.width canvas.height = viewport.height const renderContext = { canvasContext: ctx, viewport } page.render(renderContext) }) } </script>
如果要一次性展示全部页面的话,可以将代码修改成:
<template>
<div id="pdf-view">
<canvas v-for="page in state.pdfPages" :key="page" :id="`page-${page}`" />
<div id="text-view"></div>
</div>
</template>
修改页面渲染函数:
<script setup>
function renderPage(num) {
pdfDoc.getPage(num).then((page) => {
// 绑定 id 值对应的元素
const canvas = document.getElementById(`page-${num}`);
...
page.render(renderContext);
// state.pdfPages 为 pdf 文件总页数
if (num < state.pdfPages) {
renderPage(num + 1);
}
});
}
</script>
注意: 一次性渲染全部页面可能会出现加载缓慢或卡顿的问题,可以需要做相应的优化。
浏览器警告:
解决方案:
在 getDocument
方法中追加 cMapUrl
和 cMapPacked
参数:
PDF.getDocument({
url,
cMapUrl: 'https://cdn.jsdelivr.net/npm/pdfjs-dist@2.16.105/cmaps/',
cMapPacked: true,
})
注:cMapUrl
参数可指定为本地文件路径,可在路径 node_modules/pdfjs-dist/cmaps
中获取。通过测试发现,该警告即便不处理依然不影响页面展示,但是在后续的文本选中功能上可能会受影响。
在文件预览的基础上添加以下代码:
import { TextLayerBuilder } from 'pdfjs-dist/web/pdf_viewer.js'; const pdfjsWorker = import('pdfjs-dist/build/pdf.worker.entry') PDF.GlobalWorkerOptions.workerSrc = pdfjsWorker const eventBus = new pdfjsViewer.EventBus(); function renderPage(num) { pdfDoc.getPage(num).then((page) => { ... const renderContext = { ... } // page.render(renderContext) // 获取文本内容和渲染页面的 Promise const getTextContentPromise = page.getTextContent(); const renderPagePromise = page.render(renderContext); Promise.all([getTextContentPromise, renderPagePromise]) .then(([textContent]) => { const textLayerDiv = document.createElement('div'); // 注意:此处不要修改该元素的class名称,该元素的样式通过外部导入,名称是固定的 textLayerDiv.setAttribute('class', 'textLayer'); // 设置容器样式 textLayerDiv.setAttribute('style', ` z-index: 1; opacity: 1; background-color:#fff; transform: scale(1.1); width: 100%, height: 100%, `); // 设置容器的位置和宽高 textLayerDiv.style.left = canvas.offsetLeft + 'px'; textLayerDiv.style.top = canvas.offsetTop + 'px'; textLayerDiv.style.height = canvas.offsetHeight + 'px'; textLayerDiv.style.width = canvas.offsetWidth + 'px'; const textView = document.querySelector('#text-view'); textView.appendChild(textLayerDiv); const textLayer = new TextLayerBuilder({ // container: , textLayerDiv: textLayerDiv, pageIndex: page.pageIndex, viewport: viewport, eventBus, // textDivs: [] }); textLayer.setTextContent(textContent); textLayer.render(); }) .catch((error) => { console.error('Error rendering page:', error); }) }) }
通过测试发现,将 pdfjs-dist/web/pdf_viewer.css
路径下的 color
属性注释后可显示文本。
.textLayer span,
.textLayer br {
/* color: transparent; */
position: absolute;
white-space: pre;
cursor: text;
transform-origin: 0% 0%;
}
其他参考资料:https://github.com/mozilla/pdf.js/issues/11509
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'dispatch')
浏览器报错:
解决方案:
通过上网查找资料得知,需在 TextLayerBuilder
中追加参数 eventBus
:
const eventBus = new pdfjsViewer.EventBus();
function renderPage(num) {
pdfDoc.getPage(num).then((page) => {
...
Promise.all([getTextContentPromise, renderPagePromise])
.then(([textContent]) => {
...
const textLayer = new TextLayerBuilder({
...
eventBus,
});
...
}).catch ((error) => {...})})}
参考资料:
功能实现参考资料
pdf.js 相关参考资料
问题解决参考资料
其他
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。