当前位置: 首页 > news >正文

vue实现一个pdf在线预览,pdf选择文本并提取复制文字触发弹窗效果

[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部分(核心)

核心代码如下:

  1. 利用 PDF.getDocument获取pdf基础数据
  2. 通过canvas将pdf渲染到canvas画布上
<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多页面处理
  1. 模板处理id作为唯一标识
 <canvas v-for="page in pdfPages" :key="page" :id="`page-${page}`" />
  1. 修改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>

相关文章:

vue实现一个pdf在线预览,pdf选择文本并提取复制文字触发弹窗效果

[TOC] 一、文件预览 1、安装依赖包 这里安装了disjs-dist2.16版本&#xff0c;安装过程中报错缺少worker-loader npm i pdfjs-dist2.16.105 worker-loader3.0.8 2、模板部分 <template><div id"pdf-view"><canvas v-for"page in pdfPages&qu…...

【CSS 】Class Variance Authority CSS 类名管理工具库

1.背景、什么是 CVA&#xff1f; Class Variance Authority (CVA) 是一个用于管理 CSS 类名 的工具库&#xff0c;特别适合在 React 或 Vue 等前端框架中使用。它可以帮助你更轻松地处理组件的 样式变体&#xff08;Variants&#xff09;&#xff0c;比如按钮的不同状态&#…...

自然语言处理:文本分类

介绍 大家好&#xff0c;我这个热衷于分享知识的博主又来啦&#xff01;之前我们一起深入探讨了自然语言处理领域中非常重要的两个方法&#xff1a;朴素贝叶斯和逻辑斯谛回归。在探索的过程中&#xff0c;我们剖析了朴素贝叶斯如何基于概率原理和特征条件独立假设&#xff0c;…...

刷题记录 HOT100 贪心-2:45. 跳跃游戏 II

题目&#xff1a;45. 跳跃游戏 II 难度&#xff1a;中等 给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向后跳转的最大长度。换句话说&#xff0c;如果你在 nums[i] 处&#xff0c;你可以跳转到任意 nums[i j] 处: 0 &l…...

7.2 奇异值分解的基与矩阵

一、奇异值分解 奇异值分解&#xff08;SVD&#xff09;是线性代数的高光时刻。 A A A 是一个 m n m\times n mn 的矩阵&#xff0c;可以是方阵或者长方形矩阵&#xff0c;秩为 r r r。我们要对角化 A A A&#xff0c;但并不是把它化成 X − 1 A X X^{-1}A X X−1AX 的形…...

PDFMathTranslate安装使用

PDF全文翻译&#xff01;&#xff01;&#xff01;&#xff01; PDFMathTranslate安装使用 它是个啥 PDFMathTranslate 可能是一个用于 PDF 文件的数学公式翻译 工具。它可能包含以下功能&#xff1a; 提取 PDF 内的数学公式 将数学公式转换成 LaTeX 代码 翻译数学公式的内…...

STL之list的使用(超详解)

目录 一、list的介绍及使用 1.1 list的介绍 1.2 list的使用 1.2.1 list的构造 1.2.2 iterator的使用 1.2.3capacity&#xff08;容量相关&#xff09; 1.2.4 element access&#xff08;元素访问&#xff09; 1.2.5 modifiers&#xff08;链表修改&#xff09;…...

动态 SQL 的使用

目录 1、< if> 标签2、< trim> 标签3、< where> 标签4、< set> 标签5、< foreach> 标签 1、< if> 标签 < if test“条件语句”> xxxx < /if> 只有当条件语句满足条件&#xff0c;才会拼接 < if> 标签内容&#xff0c;因…...

【如何删除在 Linux 系统中的删除乱码文件】

如何删除在 Linux 系统中的删除乱码文件 1. 列出文件并找到乱码文件&#xff1a;2. 使用通配符&#xff08;谨慎使用&#xff09;&#xff1a;3. 转义特殊字符&#xff1a;4. 使用 find 命令&#xff1a;5. 使用 inode 号删除文件&#xff1a;6. 图形界面文件管理器&#xff1a…...

防火墙IPSec (无固定IP地址---一对多)

目录 前言 一、场景&#xff1a; 二、实现 1.拓扑图 2.配置思路 ①基础通信配置 ②PPPoE配置 ③总部的模版IPSec配置 ④分部的IPSec配置 ⑤NAT配置 3.具体配置 ①基础配置 ②详细配置和顺序 效果测试&#xff1a; ③PPPOE ①配置PPPoE ②策略放行 ③IPSec与NA…...

基于SpringBoot的智能问诊系统设计与隐私保护策略

通过SpringBoot框架&#xff0c;我们可以快速搭建一个智能问诊系统&#xff0c;为用户提供便捷的线上医疗服务。然而&#xff0c;在系统设计和实现过程中&#xff0c;如何保障用户的隐私和数据安全&#xff0c;始终是一个亟需关注的问题。本文将探讨基于SpringBoot的智能问诊系…...

DeepSeek进阶应用(一):结合Mermaid绘图(流程图、时序图、类图、状态图、甘特图、饼图)

&#x1f31f;前言: 在软件开发、项目管理和系统设计等领域&#xff0c;图表是表达复杂信息的有效工具。随着AI助手如DeepSeek的普及&#xff0c;我们现在可以更轻松地创建各种专业图表。 名人说&#xff1a;博观而约取&#xff0c;厚积而薄发。——苏轼《稼说送张琥》 创作者&…...

Ubuntu 下 nginx-1.24.0 源码分析 - ngx_init_cycle 函数

nei声明在 src/core/ngx_cycle.h ngx_cycle_t *ngx_init_cycle(ngx_cycle_t *old_cycle);实现在 src/core/ngx_cycle.c ngx_cycle_t * ngx_init_cycle(ngx_cycle_t *old_cycle) {void *rv;char **senv;ngx_uint_t i, n;ngx_log_t …...

【redis】数据类型之geo

Redis的GEO数据类型用于存储地理位置信息&#xff08;如经纬度&#xff09;&#xff0c;并提供高效的地理位置查询功能&#xff08;如计算两地距离、搜索附近地点等&#xff09;。其底层基于Sorted Set&#xff08;有序集合&#xff09;实现&#xff0c;通过Geohash编码将经纬度…...

vue3 vite或者vue2 百度地图(卫星图)离线使用详细讲解

1、在Windows上下载瓦片&#xff0c;使用的工具为: 全能电子地图下载器3.0最新版&#xff08;推荐&#xff09; 下载后解压&#xff0c;然后进入目录"全能电子地图下载器3.0最新版&#xff08;推荐&#xff09;\全能电子地图下载器3.0\MapTileDownloader" 在这个目录…...

《Python实战进阶》No17: 数据库连接与 ORM(SQLAlchemy 实战)

No17: 数据库连接与 ORM&#xff08;SQLAlchemy 实战&#xff09; 摘要 本文深入探讨SQLAlchemy在复杂场景下的高级应用&#xff0c;涵盖四大核心主题&#xff1a; 会话生命周期管理&#xff1a;通过事件钩子实现事务监控与审计追踪混合继承映射&#xff1a;结合单表/连接表继…...

工程化与框架系列(27)--前端音视频处理

前端音视频处理 &#x1f3a5; 引言 前端音视频处理是现代Web应用中的重要组成部分&#xff0c;涉及音频播放、视频处理、流媒体传输等多个方面。本文将深入探讨前端音视频处理的关键技术和最佳实践&#xff0c;帮助开发者构建高质量的多媒体应用。 音视频技术概述 前端音视…...

芋道打包时报错:缺失@unocss插件

在遇到打包时&#xff0c;报这个错误&#xff0c;提示构建失败是因为 ESLint 在加载 unocss 插件时&#xff0c;找不到 unocss/eslint-plugin 模块 解决办法&#xff1a;安装缺失的依赖&#xff1a;保证unocss/eslint-plugin已经被正确安装&#xff0c; 使用以下命令安装&…...

PY32MD320单片机 QFN32封装,内置多功能三相 NN 型预驱。

PY32MD320单片机是普冉半导体的一款电机专用MCU&#xff0c;芯片采用了高性能的 32 位 ARM Cortex-M0 内核&#xff0c;主要用于电机控制。PY32MD320嵌入高达 64 KB Flash 和 8 KB SRAM 存储器&#xff0c;最高工作频率 48 MHz。PY32MD320单片机的工作温度范围为 -40 ~ 105 ℃&…...

深入解析 configService.addListener 使用中的注意事项

在使用 Nacos 的 configService.addListener 方法进行配置监听时&#xff0c;为了确保程序的稳定性、可靠性以及高效性&#xff0c;有诸多注意事项需要我们关注。下面将对这些关键要点进行详细阐述。 一、连接稳定性 1.1 网络连接问题 Nacos 客户端与服务端通过网络进行通信&…...

Windows控制台函数:控制台读取输入函数ReadConsoleA()

目录 什么是 ReadConsoleA&#xff1f; 它长什么样&#xff1f; 怎么用它&#xff1f; 它跟 std::cin 有什么不一样&#xff1f; 注意事项 什么是 ReadConsoleA&#xff1f; ReadConsoleA 是一个 Windows API 函数&#xff0c;用来从控制台读取用户输入。想象一下&#…...

奇安信 2025 年护网蓝队初选笔试题(附答案解析)

&#x1f525; 爆款 CSDN 题库 | 超全护网蓝队笔试真题 | 含详细答案解析 &#x1f525; 熬夜为大家整理了 奇安信 2025 年护网蓝队初选笔试题&#xff0c;&#xff08;关注我我会持续更新&#xff09;涵盖 SQL 注入、Web 安全、渗透测试、二进制安全 等核心知识点&#xff0c;…...

国产编辑器EverEdit - Web预览设置

1 设置-高级-Web预览 1.1 设置说明 选择主菜单工具 -> 设置 -> 常规&#xff0c;在弹出的选项窗口中选择Web预览分类&#xff0c;如下图所示&#xff1a; 1.1.1 本地浏览HTML文件 如果用户只是在本地浏览HTML文件&#xff0c;即直接用浏览器打开HTML文件&#xff0c;确…...

P8686 [蓝桥杯 2019 省 A] 修改数组--并查集 or Set--lower_bound()的解法!!!

P8686 [蓝桥杯 2019 省 A] 修改数组--并查集 题目 并查集解析代码【并查集解】 Set 解法解析lower_bound代码 题目 并查集解析 首先先让所有的f&#xff08;i&#xff09;i&#xff0c;即每个人最开始的祖先都是自己&#xff0c;然后就每一次都让轮到那个数的父亲1&#xff08…...

HTML 编辑器推荐与 VS Code 使用教程

在进行 HTML 编程时&#xff0c;选择一款合适的 HTML 编辑器能极大地提高开发效率。以下为大家推荐几款常用且功能强大的 HTML 编辑器&#xff0c;同时详细介绍如何使用 VS Code 创建和预览 HTML 文件。 一、HTML 编辑器推荐 VS Code&#xff1a;由微软开发&#xff0c;是一款…...

MyBatis增删改查:静态与动态SQL语句拼接及SQL注入问题解析

MyBatis 是一个优秀的持久层框架&#xff0c;它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集的工作。本文将深入探讨 MyBatis 中的增删改查操作&#xff0c;重点讲解静态与动态 SQL 语句的拼接&#xff0c;并分析 S…...

在运维工作中,Lvs、nginx、haproxy工作原理分别是什么?

在运维工作中&#xff0c;LVS、NGINX和HAProxy都是常用的负载均衡和反向代理工具&#xff0c;它们在高可用性和负载均衡场景中发挥重要作用。以下是其原理和应用场景详解&#xff1a; LVS&#xff08;Linux Virtual Server&#xff09; 工作原理 LVS是基于Linux内核的负载均…...

linux学习(五)(服务器审查,正常运行时间负载,身份验证日志,正在运行的服务,评估可用内存)

服务器审查 在 Linux 中审查服务器的过程包括评估服务器的性能、安全性和配置&#xff0c;以确定需要改进的领域或任何潜在问题。审查的范围可以包括检查安全增强功能、检查日志文件、审查用户帐户、分析服务器的网络配置以及检查其软件版本。 Linux 以其稳定性和安全性而闻名…...

Java在小米SU7 Ultra汽车中的技术赋能

目录 一、智能驾驶“大脑”与实时数据 场景一&#xff1a;海量数据的分布式计算 场景二&#xff1a;实时决策的毫秒级响应 场景三&#xff1a;弹性扩展与容错机制 技术隐喻&#xff1a; 二、车载信息系统&#xff08;IVI&#xff09;的交互 场景一&#xff1a;Android Automo…...

开发环境搭建-02.后端环境搭建-熟悉项目结构

一.后端环境搭建...