最近做了一个需求,在app(ionic+angular搭建的)里面实现在线预览pdf文件,之前有相应的预览方式,但是之前pdf文件都是几百k,不大。这次的pdf文件是几十M,很大。之前的方案是把整个pdf文件都下载下来之后,再进行加载渲染。几十兆在网速不好的情况下,要下好一会儿。所以肯定要进行优化,怎么优化呢,在网上查了一下,决定采用分片下载的方案。
下面是我思考和总结的解决问题的步骤:
- 1、Pdf文件太大 —>
- 2、要做成切片下载 — >
- 3、技术选型 —>
- 4、pdf.js —>
- 5、搜索技术方案 —>
- 6、 公众号文章 —>
- 7、开始 —>
- 8、拿到后端切片数据(五页为一个切片)—>
- 9、 获取总页数和每张pdf的宽高—>
- 10、获取当前屏幕的宽度—>
- 11、 和pdf的宽度做对比得到缩小的比例—>
- 12、根据比例得出每张pdf页面渲染的宽高和整个所有页面的总高度—>
- 13、创建canvas元素,渲染pdf页面(pdf.js中的方法,可以直接渲染canvas)—>
- 14、创建div元素并且包裹canvas元素,并把div放在页面对应的位置上,使用position:absolute,绝对定位的方式。---->
- 15、 监听滚动事件,使用防抖函数,每隔200ms发一次请求—>
- 16、根据滚动的高度计算当前的pdf页面处于哪个切片 ---->
- 17、 然后根据当前页面所处的切片,去请求下一个切片,然后把请求回来的数据按照前面的方式进行渲染加载。—>
- 18、 这样的话就会做到客户无感知的加载页面—>
- 19、 达到了切片下载和用户体验的效果。—>
- 20、 更进一步的优化是只保留当前视线和前后的元素,上滑或者下拉的时候页面pdf脱离一定的范围后把这个pdf元素删除。---->
- 21、 这样就保证了页面中只有10个pdf页面的DOM元素,减少了页面中的dom元素,极大地提高了页面性能。—>
以上是pdf切片下载的方式和优化方案。
不过在方案实施的过程中还是遇到了一些坑点
Pdf切片下载遇到的坑点总结如下:
- 1、第一个坑点 监听页面滚动,这个花费了我半天的时间,首先用的是pdf页面的父级元素,结果监听不到,然后一级一级往上试,还是监听不到滚动事件。最后使用了window.addEventLister(‘scroll’),这个时候监听到了滚动事件,然后需要拿到页面滚动的高度,但是因为在各级元素中监听不到滚动事件,所以拿不到scrollTop。这个时候又搜索了大量的资料,没有找到合适的方法。最后问了同事,找到了ionic中的(ionscroll)= “scrollEvent($event)”这个事件—(思考:一个人的认知是有限的,还是需要向大牛多学习,多请教)。通过ionscroll拿到了scrollTop。这样就可以根据滚动的高度能计算到页面滚动到了哪个位置。本以为这样就可以了,返回上一页之后,页面滚动事件还在。Why?然后在离开阅读页面时做了清除监听,发现还是不行,因为全局有一个window的scroll监听事件,清除不了,所以监听事件就一直存在。又卡住了,不容易呀。想办法解决---- 通过尝试 发现了(ionscroll)= “scrollEvent($event)”在scrollEvent中监听滚动事件,并且使用防抖函数包裹一层,200秒触发一次。每次触发都重新计算时间,重新触发事件。---- 这样就实现了滚动分片下载的功能。
- 2、第二个坑点 ios的兼容性问题 继第一个坑点之后,以为一切都ok了,结果打包之后在苹果手机上运行时,影响了其他功能。所有pdf.js这个文件不能在index.html中全局引入了,那之前做的努力都白费了。所以开始找能够在ts组件中引入pdf.js这个模块的办法,(需要写一个类型声明的文件.d.ts,pdf.js目前没有)尝试了好多办法还是不行,最后在同事的帮助下找到了一篇文章 using PDF.JS with ionic3.x
根据文章中例子(npm install --save pdfjs-dist@2.0.489
npm install --save-dev @types/pdfjs-dist
),在ts组件中 import * as PDFJS from “pdfjs-dist/webpack.js”;
import { PDFPageProxy, PDFPageViewport, PDFRenderTask } from ‘pdfjs-dist’;这个插件,在浏览器上跑起来了,一切正常,但是打包之后在苹果的ios系统上跑了之后,出现了app打不开的现象,卸载安装的pdfjs-dist之后就正常了,所以这种方式引入失败了。于是又开始思考新的加载pdf文件的解决方案。 - 3、第三个坑点 上面的方案因为ios兼容性问题都失败了,所以尝试把pdf文件放在本地,在浏览器可以,但是打包之后就不行了。原因是pdf.js加载的时候需要用到http、https这样的协议方式,不支持file。
- 4、第四个坑点 尝试了上面这么多的方法,最后决定把所有的文件都放在静态服务器上,这是之前一直使用的方式。这次之所以优化是因为这次的pdf文件有点大(最大的是18M),直接加载会很慢。最后没有想出更好的方法,所以妥协了。不过会加上工具栏,里面有放大缩小和跳转页面的功能。以为一些会很顺利,结果打包后在ios上运行的时候,在加载完研报后,查看完之后返回的时候,直接退出了登录,也就是webViewer崩溃了。目前分析的原因是pdf文件太大了,导致的原因。这怎么办呢?
- 5、------最终版方案,经历上面这么多坑点,决定安卓和ios采用不同的方案,安卓按照第四个坑点的方案。Ios采取直接在浏览器中打开的,方法为:cordova.InAppBrower.open(url),这样就相当于在浏览器上打开了pdf文件。打包之后,初次加载有点慢,但是产品经理可以接受。就这样采取了这样的方案。----以上就是探索和采坑的过程,很曲折,但收获很多,值得自己去总结和思考的地方很多。
思考:
- 1、上面的坑点造成的原因有些还不清楚。
- 2、自己解决问题的能力还有些欠缺(怎么提升自己解决问题的能力,这点需要好好思考一下,包括定位问题,搜索问题的能力,有时间好好和大牛交流一下。)。
- 3、某一个解决方案,行不通了,有没有可以兜底的方案。(这个以后做一些重要的事情的时候都先思考一下)。这次是求助了同事,才顺利的解决上面的问题,可以看出自己的技术能力还有一些欠缺。
- 4、需要深挖一下问题的发生的根本原因,以后怎么能够更好的避免。
- 5、问问题之后自己一定要先思考之后,探索之后,再提出自己的疑惑点。
- 6、多和大牛多交流,多探讨。
- 7、大胆尝试,不要害怕失败。
- 8、努力,多学、多做、多尝试、多碰壁。
- 9、深入学习相关的知识。
总结:
从这次需求来看,
- 1、前期是探索—确定技术方案
- 2、分片下载pdf的尝试—
- 3、成功实现
- 4、在ios系统上行不通
- 5、找在ts中引入pdf.js的方法
- 6、找到后进行了尝试
- 7、本地运行一切正常
- 8、打包后在ios上行不通
- 9、心态有点崩溃
- 10、求助同事
- 11、尝试把pdf放在本地
- 12、方案行不通
- 13、把pdf文件放在静态服务器上
- 14、结果由于文件过大在ios上会崩溃
- 15、最后决定安卓和ios分开实现,ios用cordova中的方法在ios系统中直接打开pdf文件,安卓采用之前的方案(放在静态服务器上)。
自我反思:最后算是解决了。不过不完美,我对自己的表现不是很满意,自己还欠缺很多。