视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
Vue项目pdf(base)转图片遇到的问题及解决方法
2020-11-27 22:06:00 责编:小采
文档


大致的意思就是如果使用npm包管理器或者bower的话,引入的名字为pdfjs-dist,那么我们使用npm的方法引入这个pdfjs-dist,引入的名字就随意取名了这里我叫PDFJS

 import PDFJS from 'pdfjs-dist'

使用pdfjs-dist

这里后台传给我的是一个由pdf文件名字和pdf的base编码组成的对象的数组,我取名为pdfDataList

可以看到fileName是pdf的名字,fileVale是pdf文件的base编码,thumbnail是pdf缩略图的base编码这里用不到先不管,之前说到需要动态生成canvas节点(这里不会canvas也不要紧,只需要根据代码一步步做就能渲染canvas)

1.首先我们创建一个承载所有canvas节点的父节点,取名为pdfList

2.然后创建一个异步函数showPdf(不懂什么是异步函数的可以去查一下async/await,这里不用异步函数也可以使用promise.then的方法,但是async/await作为异步操作的终极方案最好还是学习一下)

async showPdf() { 
 }

使用querySelector选择类名为pdfList的dom节点,随后遍历后台传过来的pdfDataList数组的每一项,这里用到一个浏览器自带的atob()方法解码base,MDN上是这么解释的:

你可以使用 window.btoa() 方法来编码一个可能在传输过程中出现问题的数据,并且在接受数据之后,使用 atob() 方法再将数据解码。

语法: var decodedData = scope.atob(encodedData);

随后调用pdf.js插件的getDocument方法,getDocument是一个promise,所以使用异步函数的话前面需要加await关键字(不使用异步函数的话在方法后面加.then((pdf)=>{.......}),这个pdf对象和我这个pdf对象是同一个,同时这里暂时也没考虑异步操作出错的情况,有要求的话可以在加个catch捕获错误)

getDocument方法的参数是一个对象,对象键名为data,值为base解码后的值,此方法返回一个pdf对象,这个对象有几个属性,可以打印出来观察一下

这里我们先用到的是numPages属性,它指的是当前pdf文件有多少页

async showPdf() {
 let pdfList = document.querySelector('.pdfList') //通过querySelector选择DOM节点,使用document.getElementById()也一样
 for(let value of this.pdfDataList){ //遍历后台传过来的pdfDataList
 let base = value.fileValue //获得bas4编码
 let decodedBase = atob(base) //使用浏览器自带的方法解码
 let pdf = await PDFJS.getDocument({data: decodedBase}) //返回一个pdf对象
 let pages = pdf.numPages //声明一个pages变量等于当前pdf文件的页数
 }
 }

获取当前pdf文件的对象和当前pdf文件的所有页数后,循环遍历每个页数,执行如下操作:

1)动态创建canvas节点
2)调用pdf对象原型上的getPage()方法和getViewport()方法,依次传入当前循环的页数和canvas的缩放大小(这里不懂的可以直接复制黏贴)
3)渲染当前的canvas节点
4)调用page对象的render()方法渲染当前页,此方法也是一个promise,需要使用await关键字等到状态为resolve后再执行之后的代码
5)给显示当前页面的canvas节点一个className为canvas方便修改样式,最后把这个canvas节点插入到pdfList节点中

async showPdf() {
 let pdfList = document.querySelector('.pdfList') //通过querySelector选择DOM节点,使用document.getElementById()也一样
 for(let value of this.pdfDataList){ //遍历后台传过来的pdfDataList
 let base = value.fileValue //获得bas4编码
 let decodedBase = atob(base) //使用浏览器自带的方法解码
 let pdf = await PDFJS.getDocument({data: decodedBase}) //返回一个pdf对象
 let pages = pdf.numPages //声明一个pages变量等于当前pdf文件的页数
 for (let i = 1; i <= pages; i++) { //循环页数
 let canvas = document.createElement('canvas') 
 let page = await pdf.getPage(i) //调用getPage方法传入当前循环的页数,返回一个page对象
 let scale = 1;//缩放倍数,1表示原始大小
 let viewport = page.getViewport(scale); 
 let context = canvas.getContext('2d'); //创建绘制canvas的对象
 canvas.height = viewport.height; //定义canvas高和宽
 canvas.width = viewport.width;
 let renderContext = {
 canvasContext: context,
 viewport: viewport
 };
 await page.render(renderContext)

 canvas.className = 'canvas' //给canvas节点定义一个class名,这里我取名为canvas
 pdfList.appendChild(canvas) //插入到pdfList节点的最后
 }
 }
 } 

至此页面上就会多出一个canvas节点并且显示当前pdf文件的第一页的图片,如果当前pdf文件有多页就会渲染出多个canvas节点,有多个pdf文件就会先循环外层,然后再循环内层,把每个pdf文件的每一页都生成一个canvas节点

 

修改样式

渲染出页面后还有个要注意的点,Vue框架会给每个组件的DOM节点生成一个自定义属性,而节点动态生成的canvas节点,并没有data-v-xxxxx这样的自定义属性

而Vue会给每个组件里面的样式添加这个自定义属性,Vue框架这样做可以防止样式的相互污染(也就是style旁边的scoped属性)

我们这里可以在这个style下面再创建一个style写入样式来达到修改canvas样式的效果,但是记得这样做你整个项目里面类名叫canvas的都会获得这个样式,需要注意

写在最后

这里使用的是动态生成canvas节点然后渲染这个节点生成的图片,然而直接使用createElement生成一个节点并且频繁操作DOM会对性能有一定的影响,如果有更好的方法欢迎留言交流,感谢观看。希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

下载本文
显示全文
专题