vue:pdf.js使用细节/隐藏按钮/设置、获取当前页码/记录阅读进度/切换语言(国际化)
需求描述
在网页中预览pdf时,希望实现3点需求:1、隐藏一些功能按钮(比如下载);2、打开pdf时自动定位到最后浏览的页(记录阅读进度);3、实现国际化(在代码中更改pdf插件使用的语言)。
以上需求使用Chrome自带的pdf插件难以实现,经过调研,决定使用pdf.js来实现。
vue项目中使用pdf.js
这部分内容可以参考:vue项目中使用pdf.js预览pdf文件,原文的vue-pdf.js-demo非常有参考价值~
此处记录本杂鱼在项目中引入pdf.js时踩到的一个坑:使用iframe加载项目public文件夹下的HTML文件,可以参考vue-public文件夹。
项目public下引入的pdf.js文件(从vue-pdf.js-demo中拷贝):
需求调研
这一段落详细记录了本杂鱼实现这三点需求的过程,只需要参考代码的小伙伴可以直奔文末自取哈~
隐藏按钮
在实现了vue中使用pdf.js预览pdf后,开始处理附加的需求,从隐藏功能按钮入手;以隐藏下载按钮为例,F12找出下载按钮的id(download),如下图:
接着到viewer.js中搜索“download”,找出设置配置项的代码,如下图:
在viewer.js中搜索配置项名称“PDFViewerApplication”,可以看到它被挂载到了window对象上:
在新的标签页中预览pdf,在控制台打印出网页的window对象(window):
在iframe中预览pdf,在控制台打印出iframe的window对象(document.getElementById(“iframe的id”).contentWindow):
参照viewer.js中的配置项,在控制台直接修改相应配置,即可隐藏下载按钮:
PS:要重新显示隐藏的按钮用setAttribute(“hidden”, false)无效,需要removeAttribute(“hidden”)
设置、获取当前页码(记录阅读进度)
要在打开pdf时自动定位到上回浏览的页码,需要做到两点:1、pdf当前页码变更时,获取并记录页码;2、重新打开pdf时,当前页码设置为最后一次保存的页码。有了阅读的页数,再获取到pdf的总页数,自然就能计算出阅读进度啦~
Emm…实话实说,这有亿点运气的成分,本杂鱼在翻控制台输出的window.PDFViewerApplication的属性时,看到了这样两项:
经过观察,PDFViewerApplication.page就是当前的页码,而PDFViewerApplication.pagesCount就是pdf的总页数~此外,小伙伴们有没有发现,这两项数据打印的结果是(…),在vue中打印data里双向绑定的数据也是这样!所以直接修改PDFViewerApplication.page的值就能实现跳页:
页码变更时,pdf容器必然发生了滚动,因此只需要监听容器的滚动即可;可以通过记录并判断页码是否发生了变化实现防抖。
使用demo中的viewer.html加载pdf时,容器id为viewerContainer:
切换语言(国际化)
首先尝试切换浏览器的语言,观察到pdf.js插件显示语言会随浏览器语言变化(只尝试了简中和英语):
于是viewer.js中一定存在获取浏览器语言的代码(navigator.language),搜索出这样一个配置项:
于是继续在viewer.js中搜索“.locale”,找到这样一个函数:
可以看到,viewer.js会从pdf文件链接的哈希中获取locale配置项(也就是需要使用的语言)的值!但注意函数开头的判断语句,还需要打开pdfBugEnabled配置才能自定义语言,在viewer.js中搜索pdfBugEnabled,并将它的赋值改为true:
然鹅这样就阔以了吗?NONONO,还需要引入对应的语言包:
首先拉取pdf.js,可以看到一个“l10n”文件夹,里面存放着各种语言包;将要用到的语言包拷贝到web.locale文件夹下,并在locale.properties中引入包内的文件即可(官网没有en这个语言包,这里是拷贝了en-US这个包后修改了文件夹名称):
当然,最后不要忘记在pdf文件链接的哈希中加入locale参数哦!
参考代码
首先需要获取vue项目中使用pdf.js预览pdf文件这篇博客提供的demo:vue-pdf.js-demo,然后将需要的文件拷贝到自己项目的public下,可参考文章开头的截图;最后在项目中新建一个pdfViewer.vue,内容如下:
<!--* @Author: shenmingming* @Date: 2023-02-23 09:45:00* @LastEditors: shenmingming* @LastEditTime: 2023-02-24 10:48:19* @Description: 封装pdf.js插件
-->
<template><divv-loading="pdfLoading"class="pdf-viewer"><!-- 这里加载的pdf是接口返回网址的格式,filePath格式:https://IP/路径/文件名.pdf?token=XXX --><!-- 如果需要使用其他方式加载pdf,请参考vue-pdf.js-demo中的HelloWorld.vue --><iframeid="pdf-iframe":src="`${publicPath}/pdfjs/web/viewer.html?file=${encodeURIComponent(filePath)}#toolbar=0&locale=${localLan}`"frameborder="0"/></div>
</template><script>
export default {name: 'PdfViewer',props: {filePath: { // 文件网址type: String,default: () => ''},initPage: { // 初始页码type: Number,default: () => 1},hideBtns: { // 隐藏的pdf功能按钮type: Array,default: () => [`openFile`, `print`, `download`, `viewBookmark`, `toggle`]},localLan: { // 语言(默认简中)type: String,default: () => 'zh-CN'},},data () {return {publicPath: process.env.BASE_URL || `/`,interval: null, // 轮询pdf加载状态定时器pdfPageNow: this.initPage, // pdf当前页码pdfLoading: true, // 是否显示加载效果reloadTime: 50 // 检测加载状态50次未加载成功(15s),判断为加载失败}},mounted () {// 每300ms判断pdf加载状态,直到加载完成this.interval = setInterval(this.checkPdf, 300)},methods: {checkPdf () { // 轮询pdf文件加载状态if (!document.getElementById('pdf-iframe') || this.reloadTime-- < 1) { // 加载失败clearInterval(this.interval)return}let pdfFrame = document.getElementById('pdf-iframe').contentWindowlet maxNum = pdfFrame.document.getElementById('pageNumber').getAttribute('max')if (maxNum == 0 || maxNum == undefined) { // 直接获取页面显示的总页数,获取到了说明加载完成console.info('Loading...')} else {clearInterval(this.interval)this.hidePdfBtns()pdfFrame.PDFViewerApplication.page = this.pdfPageNow // pdf跳页this.pdfLoading = falseif (maxNum < 2) { // 只有一页的pdf,进度更新为100%console.log(`1/1, prog:100%`)} else {pdfFrame.document.getElementById('viewerContainer') // 监听pdf滚动事件.addEventListener('scroll', e => {let pdfInfo = pdfFrame.PDFViewerApplicationif (this.pdfPageNow !== pdfInfo.page) { // 防抖:当前页变化时,更新进度this.pdfPageNow = pdfInfo.pageconsole.log(`${pdfInfo.page}/${pdfInfo.pagesCount}, prog:${parseInt(pdfInfo.page / pdfInfo.pagesCount)}%`)}})}}},hidePdfBtns () { // 隐藏pdf功能按钮let pdfConfig = document.getElementById('pdf-iframe').contentWindow.PDFViewerApplication.appConfigthis.hideBtns.forEach(btn => {if (pdfConfig.toolbar[btn]) pdfConfig.toolbar[btn].hidden = trueif (pdfConfig.secondaryToolbar[`${btn}Button`]) pdfConfig.secondaryToolbar[`${btn}Button`].hidden = true})}}
}
</script><style scoped>
.pdf-viewer,
iframe {width: 100%;height: 100%;
}
</style>
需要注意的是:
1、这段参考代码加载的pdf是接口返回网址的格式,filePath格式类似“https://IP/路径/文件名.pdf?token=XXX”,如果需要使用其他方式加载pdf,请参考vue-pdf.js-demo中的HelloWorld.vue;
2、切换语言(国际化)还需要打开viewer.js中的配置开关,以及在项目中引入对应的语言包,具体请参考需求调研部分
最后,在需要的地方调用pdfViewer组件,自行按需调试即可~★▼★~
参考文档
[1] pdf.js
[2] vue项目中使用pdf.js预览pdf文件
[3] vue-public文件夹
[4] 哈希(location.hash详解)
相关文章:

vue:pdf.js使用细节/隐藏按钮/设置、获取当前页码/记录阅读进度/切换语言(国际化)
需求描述 在网页中预览pdf时,希望实现3点需求:1、隐藏一些功能按钮(比如下载);2、打开pdf时自动定位到最后浏览的页(记录阅读进度);3、实现国际化(在代码中更改pdf插件使…...

RocketMQ实现延迟队列精确到秒级实现
前言篇:为了节约成本,决定通过自研来改造rocketmq,添加任意时间延迟的延时队列,开源版本的rocketmq只有支持18个等级的延迟时间,其实对于大部分的功能是够用了的,但是以前的项目,全部都是使用了…...

线性数据结构:数组 Array
一、前言数组是数据结构还是数据类型?数组只是个名称,它可以描述一组操作,也可以命名这组操作。数组的数据操作,是通过 idx->val 的方式来处理。它不是具体要求内存上要存储着连续的数据才叫数组,而是说,…...

大数据开发-Hive
1、hive简介 hive是基于Hadoop的一个数据仓库工具,用于分析数据的。可以将结构化数据文件映射为一张数据库表,并提供类SQL查询功能 注:hive-SQL or HQL or类SQL 和标准SQL还是有一点点区别的 本质是SQL转换为MapReduce程序 用途࿱…...
《程序员新声》-Tech Lead 如何带领团队
收听本期播客 谢谢收听程序员新声,这是一款来自思特沃克(Thoughtworks)的播客节目。在这里,我们不仅讨论软件和技术领域的现状和未来,更关注程序员的成长世界。如何学习,如何晋升,如何带领团队…...
每日算法面试题
🧝♂️算法题 实现 pow(x, n) ,即计算 x 的 n 次幂函数(即,xn)。 示例 1:输入:x = 2.00000, n = 10 输出:1024.00000示例 2:输入:x = 2.10000, n = 3 输出:9.26100示例 3:输入:x...
高质量前端之自动化测试
前端自动化测试:Testing Library 篇 引言 前端测试 静态测试 eslint、TypeScript 单元测试 jest、mocha 集成测试 enzyme、react-testing-library、mock 爬虫 前后端解耦 为什么要引入自动化测试 测试可以让开发者站在用户的角度考虑问题,通过测试的手…...

2023不伤人脉的全新商城分销,一劳永逸的消费分红
2023不伤人脉的全新商城分销,一劳永逸的消费分红 2023-02-24 11:52梦龙 2023不伤人脉的全新商城分销,一劳永逸的消费分红 如今是流量为王的时代,但是如何将流量转化为忠实客户是个难题。不再是单向的买卖关系,而是从对产品的关注…...
【代码随想录训练营】【Day21】第六章|二叉树|530.二叉搜索树的最小绝对差|501.二叉搜索树中的众数|236. 二叉树的最近公共祖先
二叉搜索树的最小绝对差 题目详细:LeetCode.530 这道题使我第一次了解到二叉树的双指针遍历法,详细可以先查看卡哥的讲解视频:《代码随想录 — 二叉搜索树中的众数》 利用二叉搜索树的特点: 中序遍历二叉搜索树得到一个有序序…...

leaflet 导出图片,打印图片(A4横版或竖版)
第093个 点击查看专栏目录 本示例的目的是介绍如何在vue+leaflet中打印图片导出图片。一个简单的leaflet插件示例,添加了一个图标来打印或导出地图。 直接复制下面的 vue+openlayers源代码,操作2分钟即可运行实现效果. 文章目录 示例效果配置方式示例源代码(共85行)安装插…...

Java面向对象:继承特性的学习
本文介绍了面向对象的继承特性: 什么是继承 继承的概念 Java中继承的语法 在继承下父类成员的访问 super和this关键字 父类和子类构造方法 在继承下类中出现初始化代码的执行顺序 父类成员的访问权限对子类的可见性 Java的继承关系 final关键字 认识继承和组合关系 继承特性的学…...

问答系统(QA)调研
引言 智能问答系统广泛用于回答人们以自然语言形式提出的问题,经典应用场景包括:智能语音交互、在线客服、知识获取、情感类聊天等。根据QA任务,可以将QA大致分为5大类,分别为: 文本问答(text-based QA&am…...

商务租车的三大优势吸引企业以租代购
随着社会机经济的高速发展,租车模式的日益盛行,租车不仅仅是受个体户的青睐,而作为环保经济的出行方式也让越来越多的企业开始选择以租代买,据调查统计,最早开始商务租车的群体是外企。而近几年,国内的很多…...

蓝桥杯的比赛流程和必考点
蓝桥杯的比赛流程和必考点 距省赛仅1个多月!蓝桥杯的比赛流程和必考点,你还不清楚? “巷子里的猫很自由,却没有归宿;围墙里的狗有归宿,终身都得低头。人生这道选择题,怎么选都会有遗憾。” 但不…...

【数据结构】红黑树
红黑树一、红黑树的概念二、红黑树的接口2.1 插入三、验证四、源码一、红黑树的概念 红黑树也是一个二叉搜索树,他是通过对任何一条从根到叶子的路径上各个结点着色方式的限制,最长路径长度不超过最短路径长度的 2 倍保持近似平衡。他在每个节点添加了一…...
从C++的角度理解C#的Event
由于技术背景是C起家的,所以对于C的概念很清楚,遇到C#的EVENT时候,总感觉这个概念比较抽象,不容易理解,但是当使用函数指针和回调函数来理解EVENT的时候,这个概念就清晰了。 首先对于EVENT来讲,…...

商城进货记录交易-课后程序(JAVA基础案例教程-黑马程序员编著-第七章-课后作业)
【实验7-2】商城进货记录交易 【任务介绍】 1.任务描述 每个商城都需要进货,而这些进货记录整理起来很不方便,本案例要求编写一个商城进货记录交易的程序,使用字节流将商场的进货信息记录在本地的csv文件中。程序具体要求如下: …...

【正点原子FPGA连载】第十七章双核AMP实验 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南
1)实验平台:正点原子MPSoC开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id692450874670 3)全套实验源码手册视频下载地址: http://www.openedv.com/thread-340252-1-1.html 第十七章双核AMP…...

内存管理框架---页(一)
文章目录物理内存的模型非一致内存访问--NUMA一致内存访问模型--UMA内存管理架构页页框管理页描述符页描述符字段flags字段详解gfp_mask 标志获得页alloc_pages__get_free_pages获得填充为0的页释放页kmallocvmalloc参考资料你用心写的每一篇文章,可能会带别人和自己…...
华为OD机试真题Python实现【流水线】真题+解题思路+代码(20222023)
流水线 题目 一个工厂有m条流水线 来并行完成n个独立的作业 该工厂设置了一个调度系统 在安排作业时,总是优先执行处理时间最短的作业 现给定流水线个数m 需要完成的作业数n 每个作业的处理时间分别为 t1,t2...tn 请你编程计算处理完所有作业的耗时为多少 当n > m时 首先…...

19c补丁后oracle属主变化,导致不能识别磁盘组
补丁后服务器重启,数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后,存在与用户组权限相关的问题。具体表现为,Oracle 实例的运行用户(oracle)和集…...

MFC内存泄露
1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...

用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...

AI病理诊断七剑下天山,医疗未来触手可及
一、病理诊断困局:刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断",医生需通过显微镜观察组织切片,在细胞迷宫中捕捉癌变信号。某省病理质控报告显示,基层医院误诊率达12%-15%,专家会诊…...

无人机侦测与反制技术的进展与应用
国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机(无人驾驶飞行器,UAV)技术的快速发展,其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统,无人机的“黑飞”&…...

GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...

Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...