【PDF.js】2023 最新 PDF.js 在 Vue3 中的使用

因为自己写业务要定制各种 pdf 预览情况(可能),所以采用了 pdf.js 而不是各种第三方封装库,主要还是为了更好的自由度。

一、PDF.js 介绍

官方地址
中文文档

PDF.js 是一个使用 HTML5 构建的便携式文档格式查看器。
pdf.js 是社区驱动的,并由 Mozilla 支持。我们的目标是为解析和呈现 PDF 创建一个通用的、基于 Web 标准的平台。

二、 安装方法

1、下载 pdf.js

下载地址
在这里插入图片描述
我下载的版本是 pdfjs-4.0.189-dist
在这里插入图片描述

2、解压包并放到项目中

解压后将完整文件夹放到 vue3 的 public 文件夹内
在这里插入图片描述

3、屏蔽跨域错误,允许跨域

web/viewer.mjs 内找到搜索 throw new Error("file origin does not match viewer's") 并注释掉,如果不注释,可能会出现跨域错误,无法正常预览文件
在这里插入图片描述
这样就算安装完成了,后面我们开始在项目中使用。

三、基础使用

1、创建 PDF 组件

我们可以创建一个 PDF 组件,代码如下:

<script setup lang="ts">
import { onMounted, ref } from 'vue';
interface Props {url: string; // pdf文件地址
}
const props = defineProps<Props>();
const pdfUrl = ref(''); // pdf文件地址
const fileUrl = '/pdfjs-4.0.189-dist/web/viewer.html?file='; // pdfjs文件地址onMounted(() => {// encodeURIComponent() 函数可把字符串作为 URI 组件进行编码。// 核心就是将 iframe 的 src 属性设置为 pdfjs 的地址,然后将 pdf 文件的地址作为参数传递给 pdfjs// 例如:http://localhost:8080/pdfjs-4.0.189-dist/web/viewer.html?file=http%3A%2F%2Flocalhost%3A8080%2Fpdf%2Ftest.pdfpdfUrl.value = fileUrl + encodeURIComponent(props.url);
});
</script><template><div class="container"><iframe :src="pdfUrl" width="100%" height="100%"></iframe></div>
</template><style scoped lang="scss">
.container {width: 100%;height: 100%;
}
</style>

2、使用组件

比如我们需要预览 public 下的一个 test.pdf 文件

<div class="pdf-box"><PDF url="/public/test.pdf" />
</div>

下面是界面默认预览效果
在这里插入图片描述

四、进阶使用

1、页面跳转(传参)

比如我们要跳到第 10 页,我们可以在地址里面添加参数 &page=${10}

pdfUrl.value = fileUrl + encodeURIComponent(props.url) + `&page=${10}`;

viewer.mjs 找到 setInitialView 函数,注意是下面这个:
在这里插入图片描述
重点:在函数末尾最下面添加下面的跳转代码(写在上面会报错,因为还没有获取到实例)

    console.log(this.pdfViewer);// 获取url参数function getQueryVariable(variable) {var query = window.location.search.substring(1);var vars = query.split('&');for (var i = 0; i < vars.length; i++) {var pair = vars[i].split('=');if (pair[0] == variable) {return pair[1];}}return false;}// 跳转到指定页const page = getQueryVariable('page');console.log(page);if (page) {this.pdfViewer.currentPageNumber = Number(page);}

2、文本标注(传参)

某些时候我们需要跳转到指定页面,然后自动标注文本,这个时候就需要自动标注了
在这里插入图片描述
代码跟跳转一样,写在后面就可以了

    // 自动高亮文本(要解码)decodeURIComponent: 解码const markText = decodeURIComponent(getQueryVariable('markText'));console.log('markText===>', markText);if (markText) {// 对查询输入框进行赋值document.getElementById('findInput').value = markText;// 点击高亮按钮实现高亮显示关键词document.getElementById('findHighlightAll').click();}

目前我还没有找到批量标注的办法,批量标注建议还是使用下面页面+坐标,遮罩的方法
在这里插入图片描述

3、添加遮罩高亮(页码+坐标)

主要是为了解决批量标注的问题,因为 pdfjs 原生只支持单文本,不支持批量,要修改大量源码(我能力不行,太难了😥)

所以还是换了种方案,就是后端返回页码+坐标,添加遮罩层渲染的方式。

这种方法主要是找到渲染的 dom元素,因为渲染的pdf有一个叫做 data-page-number="1" 的属性,因此我们可以通过 js 的 querySelectorAll 选择器找到对应属性的 dom 元素,然后再操作添加遮罩就可以了,代码放在下面。
在这里插入图片描述

    // 测试的坐标const content_pos_1 = {x: 0.5135954145019941,y: 0.4662730487881233,};const content_pos_2 = {x: 0.7135954145019941,y: 0.8662730487881233,};// 查找属性 data-page-number='页码' 的 dom 元素const pageList = document.querySelectorAll(`[data-page-number='${page}']`);console.log('查询到的dom列表===>\n', pageList[1]);// 查询到的第一个是左侧小菜单页码div,第二个是才是展示的divconst pageView = pageList[1];console.log('右侧展示的dom===>\n', pageView);// 在元素上画一个divconst div = document.createElement('div');div.style.width = (content_pos_2.x - content_pos_1.x) * 100 + '%';div.style.height = (content_pos_2.y - content_pos_1.y) * 100 + '%';div.style.backgroundColor = 'rgb(255, 255, 0, 0.1)';div.style.position = 'absolute';div.style.top = content_pos_1.y * 100 + '%';div.style.left = content_pos_1.x * 100 + '%';div.style.zIndex = '1'; // pdfjs 文本的层级是2 所以这里要设置为1 放着不能复制pageView.appendChild(div);

渲染到pdf上就是下面的样子:
在这里插入图片描述

4、添加遮罩高亮(缩放动态更新)

因为 pdf 会缩放的缘故,缩放的话会重新更新 pdf ,我们添加的 div 就会消失,所以我们要在重新更新的时候重新添加,源码内部重新添加的函数在这个位置: #updateUIState
在这里插入图片描述
我们只需要将修改后重新添加的代码放在尾部就行
首先我们要修改第三部分的代码

   // 测试的坐标const content_pos_1 = {x: 0.5135954145019941,y: 0.4662730487881233,};const content_pos_2 = {x: 0.7135954145019941,y: 0.8662730487881233,};// pdf 缩放会重新设置,所以放在window保存,其他地方要用window.page = page;window.shade = {width: (content_pos_2.x - content_pos_1.x) * 100 + '%',height: (content_pos_2.y - content_pos_1.y) * 100 + '%',top: content_pos_1.y * 100 + '%',left: content_pos_1.x * 100 + '%',};console.log(window.shade);// 查找属性 data-page-number='页码' 的 dom 元素const pageList = document.querySelectorAll(`[data-page-number='${page}']`);console.log('查询到的dom列表===>\n', pageList[1]);// 查询到的第一个是左侧小菜单页码div,第二个是才是展示的divconst pageView = pageList[1];console.log('右侧展示的dom===>\n', pageView);// 在元素上画一个divconst div = document.createElement('div');div.id = 'shade';div.style.width = window.shade.width;div.style.height = window.shade.height;div.style.backgroundColor = 'rgb(255, 255, 0, 0.1)';div.style.position = 'absolute';div.style.top = window.shade.top;div.style.left = window.shade.left;div.style.zIndex = '1';pageView.appendChild(div);

然后在 #updateUIState 函数的末尾添加下面的新增代码

    setTimeout(() => {if (!window.page) return;const pageList = document.querySelectorAll(`[data-page-number='${window.page}']`);const pageView = pageList[1];// 删除 id 为 shade 的元素(旧遮罩)const shade = document.getElementById('shade');if (shade) {shade.remove();}const div = document.createElement('div');div.id = 'shade';div.style.width = window.shade.width;div.style.height = window.shade.height;div.style.backgroundColor = 'rgb(255, 255, 0, 0.1)';div.style.position = 'absolute';div.style.top = window.shade.top;div.style.left = window.shade.left;div.style.zIndex = '1';pageView.appendChild(div);}, 500);

最终效果如下:
在这里插入图片描述
ps:如果要做大量的页面+坐标渲染(后端返回的是个数组),修改下上面的代码逻辑就行,传参自己写,不难的

当然,也可以看下面的代码哈哈哈,我还是写出来吧

5、添加遮罩高亮(数组批量跨页渲染)

假设后端返回的数据格式是这样的,是一个包含 页码、坐标的标注数组,我们需要在每个页码内渲染遮罩
在这里插入图片描述

我们就需要这样传参
在这里插入图片描述
setInitialView(storedHash, { rotation, sidebarView, scrollMode, spreadMode } = {}) 初始化函数中:

    window.content_pos = JSON.parse(decodeURIComponent(getQueryVariable('content_pos')));console.log(window.content_pos[0]);window.content_pos.forEach((item, index) => {const page = item.page_no;const shade = {width: (item.right_bottom.x - item.left_top.x) * 100 + '%',height: (item.right_bottom.y - item.left_top.y) * 100 + '%',top: item.left_top.y * 100 + '%',left: item.left_top.x * 100 + '%',};console.log(shade);const pageList = document.querySelectorAll(`[data-page-number='${page}']`);const pageView = pageList[1];const div = document.createElement('div');div.id = 'shade' + index;div.style.width = shade.width;div.style.height = shade.height;div.style.backgroundColor = 'rgb(255, 255, 0, 0.1)';div.style.position = 'absolute';div.style.top = shade.top;div.style.left = shade.left;div.style.zIndex = '1';pageView.appendChild(div);});

#updateUIState(resetNumPages = false) 更新函数中:

    setTimeout(() => {if (window.content_pos) {window.content_pos.forEach((item, index) => {const shadeEl = document.getElementById('shade' + index);if (shadeEl) {shadeEl.remove();}const page = item.page_no;const shade = {width: (item.right_bottom.x - item.left_top.x) * 100 + '%',height: (item.right_bottom.y - item.left_top.y) * 100 + '%',top: item.left_top.y * 100 + '%',left: item.left_top.x * 100 + '%',};const pageList = document.querySelectorAll(`[data-page-number='${page}']`);const pageView = pageList[1];const div = document.createElement('div');div.id = 'shade' + index;div.style.width = shade.width;div.style.height = shade.height;div.style.backgroundColor = 'rgb(255, 255, 0, 0.1)';div.style.position = 'absolute';div.style.top = shade.top;div.style.left = shade.left;div.style.zIndex = '1';pageView.appendChild(div);});}}, 500);

效果展示,可以实现跨页,多页渲染
在这里插入图片描述

后续根据开发业务持续更新😁

感谢大佬们的无私分享

详细|vue中使用PDF.js预览文件实践
vue3项目使用pdf.js插件实现:搜索高亮、修改pdf.js显示的页码、向pdf.js传值、控制搜索、处理接口文件流
pdf.js根据路径里传参数高亮显示关键字(跳转到对应页面)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/166972.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ThreeJs实现简单的动画

上一节实现可用鼠标控制相机的方式实现动态效果&#xff0c;但很多时候是需要场景自己产恒动态效果&#xff0c;而不是通过鼠标拖动&#xff0c;此时引入一个requestAnimationFrame方法&#xff0c;它实际上是通过定时任务的方式&#xff0c;每隔一点时间改变场景中内容后重新渲…

Ant Design Vue 树形表格计算盈收金额

树形表格计算 一、盈收金额计算1、根据需要输入的子级位置&#xff0c;修改数据2、获取兄弟节点数据&#xff0c;并计算兄弟节点的金额合计3、金额合计&#xff0c;遍历给所有的父级 一、盈收金额计算 1、根据需要输入的子级位置&#xff0c;修改数据 2、获取兄弟节点数据&am…

销售管理系统的实用性怎么样?

销售管理系统好用吗&#xff1f;好用&#xff0c;销售管理系统可以管理销售流程、自动化大量重复性工作&#xff0c;让销售人员从琐碎的任务中挣脱出来&#xff0c;投入到客户跟进和维护客户关系之中。那么&#xff0c;CRM系统的好用体现在哪些方面&#xff1f; 1.加速销售流程…

react中的state

没想到hooks中也有state这一说法 看下面的两个案例 1、无state变化不会执行父子函数 2、有state更改执行父子函数

深度学习之六(自编码器--Autoencoder)

概念 自编码器(Autoencoder)是一种神经网络架构,用于无监督学习和数据的降维表示。它由两部分组成:编码器(Encoder)和解码器(Decoder)。 结构: 编码器(Encoder): 接收输入数据并将其压缩为潜在表示(latent representation),通常比输入数据的维度要低。编码器的…

最详细的软件测试面试题整理与分析

前言 时光荏苒&#xff0c;一转眼到了2023年末尾&#xff0c;2024年也快要来了&#xff0c;人员就业市场以往的寒冬也貌似有了转暖的迹象&#xff0c;身边大批的就业人员也开始了紧张的备战之中。 近几周也和多家合作公司的HR进行了沟通&#xff0c;发现虽然岗位就业情况较去年…

vue3中引入svg矢量图

vue3中引入svg矢量图 1、前言2、安装SVG依赖插件3、在vite.config.ts 中配置插件4、main.ts入口文件导入5、使用svg5.1 在src/assets/icons文件夹下引入svg矢量图5.2 在src/components目录下创建一个SvgIcon组件5.3 封装成全局组件&#xff0c;在src文件夹下创建plugin/index.t…

一键创新 | 拓世法宝AI智能直播一体机激发房产自媒体创造力

在数字化时代&#xff0c;房产销售已然不再是传统的模式。随着社交媒体和自媒体的兴起&#xff0c;短视频直播成为房产自媒体营销的新风口。然而&#xff0c;行业也面临着诸多挑战&#xff0c;如何更好地利用新媒体拓展市场&#xff0c;提升自媒体效果成为摆在业内人士面前的难…

JMeter测试报错422 Unprocessable Entity

添加HTTP信息头&#xff1a; ​ HTTP请求-》添加-〉配置元件-》HTTP信息头管理器 ​ 如果需要送json&#xff0c;需要添加Content-Type:application/json&#xff0c;否则会报【422 Unprocessable Entity】

好用的CRM系统到底有多重要?怎么选?

我们都知道&#xff0c;CRM软件可以让企业效率加倍。但如果选错了CRM&#xff0c;企业损失点钱是小&#xff0c;客户转化率下降才是大。下面我们就来说说&#xff0c;市面上有哪些好用的CRM&#xff1f;以及好用的CRM软件的重要性。 好用的CRM软件的重要性&#xff1a; 客户管…

Qt 软件调试(一) Log日志调试

终于这段时间闲下来了&#xff0c;可以系统的编写Qt软件调试的整个系列。前面零零星星的也有部分输出&#xff0c;但终究没有形成体系。借此机会&#xff0c;做一下系统的总结。慎独、精进~ 日志是有效帮助我们快速定位&#xff0c;找到程序异常点的实用方法。但是好的日志才能…

百度 文心一言 sdk 试用

JMaven Central: com.baidu.aip:java-sdk (sonatype.com) Java sdk地址如上&#xff1a; 文心一言开发者 文心一言 (baidu.com) ERNIE Bot SDK https://yiyan.baidu.com/developer/doc#Fllzznonw ERNIE Bot SDK提供便捷易用的接口&#xff0c;可以调用文心一言的能力&#…

口袋参谋:如何避免宝贝被降权?这招屡试屡爽!

​至少99.99999%的店铺在今年都被降权过&#xff01;各家店铺被降权的原因&#xff0c;无非就一个原因&#xff0c;那就是s单&#xff01; s单的风险也就两种&#xff0c;一是操作问题&#xff0c;二是账号问题。 操作问题被降权&#xff0c;这个大家都心知肚明&#xff0c;s…

5大原因,设备校准为什么是实验室搬迁后的首要任务?

实验室搬迁是一个复杂而紧张的过程。要考虑的事情太多&#xff0c;很容易忽视您最重要的任务之一——检查设备在新环境中的性能。 校准对于确保设备安全运行和遵守监管标准至关重要。 1.保持合规性并遵守法律要求 生物技术和制药等行业有特定的校准要求&#xff0c;实验室必…

浅谈安科瑞直流电表在印尼某基站的应用

摘要&#xff1a;本文介绍了安科瑞直流电表在印尼的应用。主要用于印尼某基站的电流电压电能的计量&#xff0c;配合霍尔传感器对基站进行计量。 Abstract: This article introduces the application of Acrel DC meters in base station in Indonesia.The device is measuri…

如何做好测试管理岗?深度分析职业规划

在给学生做职业规划的时候&#xff0c;经常就有同学说&#xff1a;我以后要做管理岗&#xff01;其实对于很多刚入行的同学&#xff0c;可能说这句话的时候并没有真正理解管理岗需要做什么事&#xff0c;以及需要具备什么样的技能。所以&#xff0c;作为资深测试经理&#xff0…

飞翔的小鸟——Java

一、创建文件、包、类、插入图片文件 二、app包 1、Gameapp类&#xff08;运行游戏&#xff09; package app;import main.GameFrame;public class Gameapp {public static void main(String[] args) {//游戏的入口new GameFrame();} } 三、main包 1、Barrier&#xff08…

无需外接显示器,直接使用windows安装树莓派系统并可远程桌面登录

准备工作: 1.安装树莓派官方烧录工具 raspberry pi imager 2.下载树莓派系统镜像(也可选择在线下载安装) 打开imager工具&#xff0c;选择需要安装包树莓派版本 点击"NEXT"&#xff0c;在弹出的选项中选择编辑设置。 设置登录名和密码&#xff0c;已经所连接的wif…

统一用户桌面壁纸怎么设置

统一用户桌面壁纸的设置方法有多种&#xff0c;以下列举两种&#xff1a; 方法一&#xff1a;个人更换壁纸 1、右键桌面&#xff0c;鼠标选择“个性化”。 2、进入个性化之后&#xff0c;单击下面的“桌面背景”图标。 3、点击“浏览”选择自己备好的桌面壁纸&#xff0c;点击…

昇腾Atlas 200I DK A2实现安全帽识别

文章目录 环境依赖编译测试总结 环境依赖 软件版本说明获取方式mxVision5.0.RC2mxVision软件包获取方式Ascend-CANN-toolkit6.2.RC2Ascend-cann-toolkit开发套件包获取方式Ubuntu22.04 代码仓库地址&#xff1a; https://gitee.com/ascend/ascend_community_projects/tree/31…