[TOC]
一、文件预览
1、安装依赖包
这里安装了disjs-dist@2.16版本,安装过程中报错缺少worker-loader
npm i pdfjs-dist@2.16.105 worker-loader@3.0.8
2、模板部分
<template><div id="pdf-view"><canvas v-for="page in pdfPages" :key="page" :id="pdfCanvas" /><div id="text-view"></div></div>
</template>
3、js部分(核心)
核心代码如下:
<script>import * as pdfjsViewer from "pdfjs-dist/web/pdf_viewer.js";import "pdfjs-dist/web/pdf_viewer.css";import * as PDF from "pdfjs-dist/webpack";export default {name: "",components: {},data() {return {pdfPages: 1,pdfPath: "http://localhost:8080/qfnext.pdf",// 总页数pdfPages: 1,// 页面缩放pdfScale: 1,pdfDoc: null,};},mounted() {this.loadFile(this.pdfPath);},methods: {loadFile(url) {PDF.getDocument({url,cMapUrl: "https://cdn.jsdelivr.net/npm/pdfjs-dist@2.16.105/cmaps/",cMapPacked: true,}).promise.then((pdf) => {this.pdfDoc = pdf;// 获取pdf文件总页数this.pdfPages = pdf.numPages;this.$nextTick(() => {this.renderPage(1); // 从第一页开始渲染});});},renderPage(num) {this.pdfDoc.getPage(num).then((page) => {const canvas = document.getElementById(`pdfCanvas`);const ctx = canvas.getContext("2d");const viewport = page.getViewport({ scale: this.pdfScale });canvas.width = viewport.width;canvas.height = viewport.height;const renderContext = {canvasContext: ctx,viewport,};page.render(renderContext);});},},};
</script>
可能出现的问题:
(1) 页面文字可选中,但文本不可见
通过测试发现,将 pdfjs-dist/web/pdf_viewer.css 路径下的 color 属性注释后可显示文本。
.textLayer span,
.textLayer br {/* color: transparent; */position: absolute;white-space: pre;cursor: text;transform-origin: 0% 0%;
}
pdf_87">pdf多页面处理
- 模板处理id作为唯一标识
<canvas v-for="page in pdfPages" :key="page" :id="`page-${page}`" />
- 修改canvas渲染逻辑,主要通过递归的方式逐一渲染
renderPage(num) {this.pdfDoc.getPage(num).then((page) => {const canvas = document.getElementById(`page-${num}`);const ctx = canvas.getContext("2d");const viewport = page.getViewport({ scale: this.pdfScale });canvas.width = viewport.width;canvas.height = viewport.height;const renderContext = {canvasContext: ctx,viewport,};page.render(renderContext);if (num < this.pdfPages) {this.renderPage(num + 1);}});},
二、文本选中与弹窗(核心代码)
Promise.all([getTextContentPromise, renderPagePromise]).then(([textContent]) => {const textLayerDiv = document.createElement("div");// 注意:此处不要修改该元素的class名称,该元素的样式通过外部导入,名称是固定的textLayerDiv.setAttribute("class", "textLayer");// 设置容器样式textLayerDiv.setAttribute("style",`z-index: 1;opacity: .2;// 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();// 当选择文本后鼠标取消点击时触发textLayerDiv.addEventListener("mouseup", () => {// // 隐藏文本层// textLayerDiv.style.display = 'none';// 是否选择了文本const isTextSelected =window.getSelection().toString().trim() !== "";if (isTextSelected) {//选择的文本内容const selectedText = window.getSelection().toString();console.log("Selected text:", selectedText);if (selectedText) {alert(selectedText);}}});}).catch((error) => {console.error("Error rendering page:", error);});
三、完整代码如下
<template><div id="pdf-view"><canvas v-for="page in pdfPages" :key="page" :id="`page-${page}`" /><div id="text-view"></div></div>
</template><script>import * as pdfjsViewer from "pdfjs-dist/web/pdf_viewer.js";import "pdfjs-dist/web/pdf_viewer.css";import * as PDF from "pdfjs-dist/webpack";// import { getDocument } from 'pdfjs-dist/webpack';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();export default {name: "",components: {},data() {return {pdfPages: 1,pdfPath: "http://localhost:8080/qfnext.pdf",// 总页数pdfPages: 1,// 页面缩放pdfScale: 1,pdfDoc: null,};},mounted() {this.loadFile(this.pdfPath);},methods: {loadFile(url) {PDF.getDocument({url,cMapUrl: "https://cdn.jsdelivr.net/npm/pdfjs-dist@2.16.105/cmaps/",cMapPacked: true,}).promise.then((pdf) => {this.pdfDoc = pdf;// 获取pdf文件总页数this.pdfPages = pdf.numPages;this.$nextTick(() => {this.renderPage(1); // 从第一页开始渲染});});},renderPage(num) {this.pdfDoc.getPage(num).then((page) => {const canvas = document.getElementById(`page-${num}`);const ctx = canvas.getContext("2d");const viewport = page.getViewport({ scale: this.pdfScale });canvas.width = viewport.width;canvas.height = viewport.height;const renderContext = {canvasContext: ctx,viewport,};// 获取文本内容和渲染页面的 Promiseconst getTextContentPromise = page.getTextContent();const renderPagePromise = page.render(renderContext);if (num < this.pdfPages) {this.renderPage(num + 1);}Promise.all([getTextContentPromise, renderPagePromise]).then(([textContent]) => {const textLayerDiv = document.createElement("div");// 注意:此处不要修改该元素的class名称,该元素的样式通过外部导入,名称是固定的textLayerDiv.setAttribute("class", "textLayer");// 设置容器样式textLayerDiv.setAttribute("style",`z-index: 1;opacity: .2;// 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();// 当选择文本后鼠标取消点击时触发textLayerDiv.addEventListener("mouseup", () => {// // 隐藏文本层// textLayerDiv.style.display = 'none';// 是否选择了文本const isTextSelected =window.getSelection().toString().trim() !== "";if (isTextSelected) {//选择的文本内容const selectedText = window.getSelection().toString();console.log("Selected text:", selectedText);if (selectedText) {alert(selectedText);}}});}).catch((error) => {console.error("Error rendering page:", error);});});},},};
</script>
<style lang="scss" scoped>.pdf-con {border: 2px solid #ccc;width: 80%;margin: auto;height: 800px;overflow: auto;// display: none;}
</style>