Vue2项目如何使用pdfjs-dist解析pdf
作者:驴肉板烧凤梨牛肉堡
先说结论
使用pdfjs-dist的2.7.570版本
使用pdfjs-dist的2.7.570版本的es5产物,该版本的es5的build产物没有特殊写法,对vue.config.js、babel.config.js的兼容性最好,不需要额外再下载其他插件,比如可选链插件等
引用方式
import * as pdfjsLib from 'pdfjs-dist/es5/build/pdf' import pdfWorker from 'pdfjs-dist/es5/build/pdf.worker.entry' pdfjsLib.GlobalWorkerOptions.workerSrc = pdfWorker pdfjsLib.GlobalWorkerOptions.isEvalSupported = false // 关闭 eval 支持(防止漏洞)
背景
某天,产品同事发现C端的资质展示页面(H5)的图片渲染有问题,经排查发现有些链接是.pdf结尾的pdf文件,最后导致某些机型无法正常渲染。如下图所示
这里有个小点: ios机型会把pdf渲染出来1页,安卓机型无法渲染pdf
遇到问题时的思考
这种情况在线上是否多,如果量级不多,个人感觉可以尝试后端进行解析PDF转成图片,在更新数据库。但这需要结合业务系统来看,因为这是“资质文件”,所以得保证业务系统在这方面的功能是怎么样的,是只能上传图片还是pdf,还是都能,不过这是后面分析才得到的结果
后端是否好解决,这需要和后端沟通
需求
能够根据pdf链接展示出他的所有页数内容,不失真,能在各个机型的web-view中运行,如安卓app、ios的app、支付小程序、微信小程序。
只做pdf解析预览功能,不需要额外功能,把内容转成图片即可。
尽量做到不修改vue.config.js、babel.config.js来解决这个问题,理想情况就是新增一个组件,然后对应页面判断是链接,最后使用下就好了。毕竟这是老项目,这些可不能乱动。
前期开发工作
与后端沟通,结果是后端不好解决,只能交给前端来解决
先问gpt,具体方案和关键依赖,可能的坑点
搜索gpt,根据得到的关键依赖(pdfjs-dist
),了解他的issue、坑点、demo等
顺便搜下相关文章,但发现质量都挺一般的,数量有点少,于是就参考gpt的,其次就是pdfjs-dist
的文档有点难看懂
具体实施
下载 pdfjs-dist
,下载时下的是最新版本,5.x.x
新建pdf-viewr.vue
组件
复制gpt给我的代码
运行项目
# gpt给的案例 import * as pdfjsLib from 'pdfjs-dist/build/pdf' import pdfWorker from 'pdfjs-dist/build/pdf.worker.entry' pdfjsLib.GlobalWorkerOptions.workerSrc = pdfWorker // 解析过程省略,主要核心是引用方式的问题
踩坑之旅
依照上述实施行为,结果就是直接报错,运行不了,于是我就开始了我的漫长踩坑之旅
我的依赖&版本
- node: 12.22.22
- @vue/cli: ^3.12.0
- babel-core: 7.0.0-bridge.0
- vue: 2.6.x
版本问题
使用pdfjs-dist遇到了非常多的版本兼容性问题,由于用的是最新版本,有很多写法,和我的对不上,于是我的想法是降版本,但一开始不知道降到多少,毕竟有1549个版本,想法是问ai,但ai回答出来的版本还是不太行,于是我就打算换个方式,找找有没有现成的封装好的组件
这里找到的是vue-pdf
,这个组件是用pdfjs-dist
+vue2
的,我大喜过望,马上下载使用,写起来很快呀,但新的问题已然埋下
vue-pdf问题
- issue数量特别多,只能说慎用,一共235个
- 这个组件在打包上线后,会无法正常加载出来,导致对应页面白屏。根据gpt的说法是可能丢失了pdfjs-dist,然后我就去找原因,这种情况先找issue,我在vue-pdf的issue中看到了有人遇到了同样的问题,然后我在某个issue中,看到了这么一句话:使用2.7.570版本。
于是我顺藤摸瓜,找到pdfjs-dist的版本记录,找到他的内容是什么,然后我就发现了一个让我很兴奋的点:
这个依赖的有build和es5的build产物!!!,这是最关键的,他的其他版本我看了几个,我发现没有es5的打包产物
用build的产物仍然存在特殊写法,比如可选链,因为我的项目没有可选链的babel插件,所以仍然不能用
但是es5的产物没有特殊写法,所以理论上用这个就能解决了,因为引用报错的问题是语法相关的兼容性问题,我又不想新增babel插件、loader依赖等
最后在我使用了这个版本后,修改了原先AI提供的案例中的引用方式,于是项目正常跑了起来,这里就不使用vue-pdf
了,使用pdfjs-dist
,用它来解析,然后转图片。
对比如下:
# 前 import * as pdfjsLib from 'pdfjs-dist/build/pdf' import pdfWorker from 'pdfjs-dist/build/pdf.worker.entry' pdfjsLib.GlobalWorkerOptions.workerSrc = pdfWorker # 后 import * as pdfjsLib from 'pdfjs-dist/es5/build/pdf' import pdfWorker from 'pdfjs-dist/es5/build/pdf.worker.entry' pdfjsLib.GlobalWorkerOptions.workerSrc = pdfWorker
病毒问题
病毒问题也是看vue-pdf
的issue才知道的
根据报告链接所提供的方案就是
pdfjsLib.GlobalWorkerOptions.isEvalSupported = false // 关闭 eval 支持(防止漏洞)
小结
为了解决pdfjs-dist在vue2的老项目的兼容性问题,最终方案就是使用pdfjs-dist@2.7.570,这样就不用影响到之前的vue.config.js、babel.config.js相关配置了。
这个过程解决兼容问题,费时费力,还以为无法解决了,不过皇天不负苦心人,这个问题还是被解决了,所以记录下。
后续计划
自己打包高版本(5.x.x)的pdfjs-dist来适应内部项目
研究vue-pdf打包上线白屏问题
接入vue3项目
分页加载优化,大文件优化
代码
pdf解析预览组件
<template> <div class="pdf-viewer"> <van-loading v-if="loading" type="spinner" size="32px" vertical>加载中</van-loading> <div v-else> <div v-if="error" class="fallback"> <p>当前信息无法加载,您可以<a :href="pdfUrl" target="_blank">点击查看</a></p> </div> <div v-else> <div v-for="(page, index) in pages" :key="index" class="pdf-page"> <img :src="page" :alt="'pdf ' + (index + 1)" class="pdf-image"> </div> </div> </div> </div> </template> <script> import { Loading } from 'vant' // ? 使用pdfjs-dist的2.7.570版本的es5产物,该版本的es5的build产物没有特殊写法,对本项目vue.config.js、babel.config.js的兼容性最好 import * as pdfjsLib from 'pdfjs-dist/es5/build/pdf' import pdfWorker from 'pdfjs-dist/es5/build/pdf.worker.entry' pdfjsLib.GlobalWorkerOptions.workerSrc = pdfWorker pdfjsLib.GlobalWorkerOptions.isEvalSupported = false // 关闭 eval 支持(防止漏洞)// 漏洞链接: https://www.venustech.com.cn/new_type/aqtg/20240514/27492.html export default { name: 'pdf-viewer', props: { pdfUrl: { type: String, required: true, }, }, components: { [Loading.name]: Loading, }, data() { return { pages: [], loading: true, error: false, } }, mounted() { this.loadPdf() }, methods: { async loadPdf() { try { const loadingTask = pdfjsLib.getDocument(this.pdfUrl) const pdf = await loadingTask.promise const pageImages = [] for (let pageNum = 1; pageNum <= pdf.numPages; pageNum++) { const page = await pdf.getPage(pageNum) const viewport = page.getViewport({ scale: 2 }) // scale 调大可提高清晰度 const canvas = document.createElement('canvas') const context = canvas.getContext('2d') canvas.width = viewport.width canvas.height = viewport.height await page.render({ canvasContext: context, viewport }).promise pageImages.push(canvas.toDataURL()) } this.pages = pageImages this.loading = false } catch (e) { console.error('PDF 加载失败:', e) this.error = true this.loading = false } }, }, } </script> <style lang="stylus" scoped> .pdf-viewer { width: 100%; overflow-x: hidden; } .pdf-image { width: 100%; display: block; object-fit: contain; } .fallback { text-align: center; color: #999; font-size: 14px; height: 100%; display: flex; justify-content: center; align-items: center; a { color: #007aff; text-decoration: underline; } } </style>
链接类型判断
// 判断文件类型(扩展名优先,fallback 为 HEAD) async detectFileType(url) { // 1. 特殊 scheme 优先判断 if (url.startsWith('data:image/')) return 'image' if (url.startsWith('data:application/pdf')) return 'pdf' if (url.startsWith('blob:')) return 'unknown' // 2. 扩展名判断(宽松匹配) if (/\.(jpe?g|png|gif|bmp|webp|svg)([\?#].*)?$/i.test(url)) return 'image' if (/\.pdf([\?#].*)?$/i.test(url)) return 'pdf' // 3. 尝试发 HEAD 请求获取 content-type try { const res = await axios.head(url) // ? 支付宝小程序如果遇到404链接会导致页面白屏,微信、安卓不会 const contentType = res.headers['content-type'] || '' if (contentType.includes('image/')) return 'image' if (contentType.includes('application/pdf')) return 'pdf' } catch (e) { console.warn('链接类型获取失败:', url, e.message) } return 'unknown' }
到此这篇关于Vue2项目如何使用pdfjs-dist解析pdf的文章就介绍到这了,更多相关Vue2解析pdf内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!