业务场景
pdf.js可以说是预览PDF的全能插件,里面内置了很多方法供开发者使用。
之前一直使用的pdf.js+canvas的形式预览PDF,但是这有一个很大的弊端,就是canvas生成的图片太糊了,而且本质上这渲染的根本不是pdf,而是一张图片,很多pdf中带有的功能这里都不能实现
比如
- pdf全局搜索
- 缩小放大任能保持清晰度
- 指定页跳转,上下一页
- 对当前预览的文件,开启在线演示模式
- 支持在 viewer.html 添加水印
- …等等操作
本文只做最基础的,能让你在移动端,PC端正常预览PDF的功能,扩展操作不做解释
下载pdf.js源码
最新版下载地址,下载哪个自己选择,我没有细看他们之间的区别,我选择的下载第一个
历史版本下载地址
如果你需要下载历史版本的话,选择你想要的版本,点击Downloads进入下载页面
这里会告诉你这个版本都做哪些优化或者其他工作,之后拉到页面最下面,点击下载第一个
下载完成之后你会得到一个压缩包,(你可能会好奇,为什么不直接npm install这种下载形式,而要下载一个压缩包,没关系继续看)
会得到一个这样目录的压缩包
build文件夹
web文件夹
OK,到这里已经完成pdf.js的下载工作
接下来我会使用vite
脚手架搭建一个新的vue3
项目作为演示
引入PDF.JS并使用他来预览我们的第一份PDF文件
这是我创建的一个空的vue3项目,刚初始化完成的,我新建了一个 pdfJSDemo.vue
文件作为演示的入口
现在,将我们刚才下载好的pdf.js
文件,放到项目的public
文件下新建的pdfJS
文件中(是不是public文件都无所谓,这里作为演示)
注意这里的viewer.html
文件,你可能在其他博客中见到这个文件,他们指的都是这个文件,我们之后所有的操作都要针对这个文件进行
我们先打开一个pdf.js
给我们提供的默认pdf
看看效果,也就是下面这个文件
打开的方式是,启动你项目之后的 开发地址 + pdfJS/web/viewer.html
(如果你是按照我的文件夹目录来的话,可以直接复制)
这是我的启动地址,所以拼接的地址就是 http://localhost:5173/pdfJS/web/viewer.html
如果你成功打开了这个页面,且没有任何报错,那就表示你的第一个预览PDF已经完成了
那么接下来我们来打开一个自己的PDF吧,自己的PDF有两种形式
- 本地的PDF文件,展示在页面上(那操作就和上面一模一样了,没啥好说的,重复上面的步骤就行)
- 后端返回的PDF链接,需要我们展示在页面上(这里以阿里云的PDF链接为例)
第二种预览形式,只需要在上面的连接上加上一个file=your-pdf-url
就行了:开发地址 + pdfJS/web/viewer.html?file=your-pdf-url
举个例子 http://localhost:5173/pdfJS/web/viewer.html?file=http://wuneng-public.oss-cn-hangzhou.aliyuncs.com/wp/infoConfig/demo/NKRRQUGX20230908050411
这时,你可能会出现这么一个错误,然后pdf无法正确渲染出来,这是因为这个pdf链接发生了跨域
你要找到 throw new Error("file origin does not match viewer's");
这段代码,并注释掉
保存之后刷新页面,这样一个链接形式的pdf就被渲染出来了
手机端的一个bug问题
因为我们使用pdfjs
主要是解决手机端浏览器无法预览PDF的情况,但是pdfjs
在手机端浏览器上有点bug
这是我使用微信浏览器打开的pdfjs官网给的一个demo页面,当在手机上进行缩放的时候,会导致显示错乱的情况,下面的图应该能很清楚的看到错乱情况
且很多其他浏览器,比如手机端的chrome浏览器,Safari浏览器,夸克浏览器会出现不同情况的缩放问题,总之很诡异。虽然官网上说他们的插件主要支持火狐浏览器,但是我试了火狐浏览器,还是有问题
手机端缩放bug,我的解决方式
- 限制页面不能进行缩放
user-scalable=no
,这可以避免(Chrome、Safari浏览器之类的缩放问题)
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
- 设置页面属性zoom为1
body {
zoom: 1; /* 设置缩放比例为1,即不缩放 */
}
- 根据页面的按钮点击事件,找到对应的源码,修改源码的缩放事件
我的理解是,在手机端使用手势缩放放大缩小pdf后,出现了错乱的情况,这时候我再手动调用一下源码中自带的
update
方法
我在源码中加了一个被我隐藏的按钮,并为其添加点击事件,在缩放完成后,调用点击事件,完成pdf的更新
.myBtn {
position: absolute;
opacity: 0;
}
在viewer.js
源码文件里,在这里添加根据 ID 获取 DOM 元素
在viewer.js
源码文件里,这一段代码中,注册DOM元素的点击事件
有很多地方的事件注册,我这里应该是截图完了,单也可能是哪里忘记截图了
- 手势结束事件后,手动触发upadte事件
const c_viewerContainer = document.getElementById('viewer')
c_viewerContainer.addEventListener('touchend', handleTouchEnd, false)
// 手势结束事件
function handleTouchEnd(event) {
myBtnUpdate.click()
}
抛砖引玉,我这个方法虽然可以解决,但是太僵硬了,为了解决而解决,肯定是有更好的办法的