vue使用pdf.js实现移动端在线PDF文件预览
pdfjs实现vue pdf预览
·
背景
产品需求涉及到动态的PDF展示,PDF是由后端去生成的,然后下发给前端在线的cdn地址,H5需要实现在线PDF预览的能力
方案
H5展示合同PDF,有很多实现方式。但是通过尝试后发现在不同操作系统会存在兼容性问题
方案 | 表现 |
---|---|
iframe的形式 | iOS:只能展示第一页,多页不能展示 Android: 弹出下载弹窗 PC:正常展示 |
embed标签 | iOS:只能展示第一页 Android: 弹出下载弹窗 PC:显示不出来 |
vue-pdf(基于pdfjs封装 | 各端都能正常展示,且可以根据需要展示PDF的全部页数,设定翻页操作,但是部署到生产环境时存在bug,且该库已经一年多没有维护了 |
pdf.js | 各端均能正常展示 |
最终选择了使用pdf.js,日常开发中如果原生标签能满足的还是尽量用简单的方案处理,但是此次需求涉及到较为复杂的PDF操作,所以对比之下还是使用了插件的形式
解决方案
<canvas
v-for="page in pdfPages"
:key="page"
:id="'pdf-canvas' + page"
/>
<script>
//以es5形式引入,解决低端浏览器兼容性问题
const PDFJS = require("pdfjs-dist/es5/build/pdf");
//pdfjs-dist的版本也是2.5.207
PDFJS.GlobalWorkerOptions.workerSrc = "https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.5.207/pdf.worker.js";
export default {
name: "Contract",
data: function () {
return {
pdfPages: [], //页数
pdfWidth: "", // 宽度
pdfSrc: '', //地址
pdfDoc: "", //文档内容
pdfScale: 1, //放大倍数
contractUrl: '', //后端返回的PDF链接
}
},
mounted() {
this.getData()
},
methods: {
getData() {
getContractUrl().then(res => {
if (res.data) {
let {contract_url, email} = res.data
this.contractUrl = contract_url
this.pdfSrc = contract_url
if(contract_url){
this.loadFile(this.pdfSrc)
}
}
}).catch(err => {
console.log('getContractUrl err', err)
})
},
loadFile(url) {
this.$Loading.show()
let loadingTask = PDFJS.getDocument(url);
loadingTask.promise.then(pdf => {
this.$Loading.hide()
this.pdfDoc = pdf;
this.pdfPages = pdf.numPages;
this.$nextTick(() => {
this.renderPage(1);
});
}).catch(err=>{
console.log(err, 'loadingTask err')
});
},
renderPage(num) {
const that = this;
this.pdfDoc.getPage(num).then(page => {
let canvas = document.getElementById("pdf-canvas" + num);
let ctx = canvas.getContext("2d");
let dpr = window.devicePixelRatio || 1;
let ratio = dpr;
// screen.availWidth 屏幕可用宽度
let viewport = page.getViewport({scale: screen.availWidth / page.getViewport({scale: this.pdfScale}).width})
// console.log(viewport,'-----viewport')
canvas.width = viewport.width * ratio;
canvas.height = viewport.height * ratio;
canvas.style.width = viewport.width + "px";
canvas.style.height = viewport.height + 'px'
that.pdfWidth = viewport.width + "px";
canvas.style.height = viewport.height + "px";
ctx.setTransform(ratio, 0, 0, ratio, 0, 0);
// 将 PDF 页面渲染到 canvas 上下文中
let renderContext = {
canvasContext: ctx,
viewport: viewport
};
page.render(renderContext);
if (this.pdfPages > num) {
this.renderPage(num + 1);
}
});
}
}
</script>
踩坑点
1、移动端适配问题
需要设置好viewport,要不然canvas渲染无法做到屏幕适配
let dpr = window.devicePixelRatio || 1; //获取设备像素比
let ratio = dpr
// screen.availWidth 屏幕可用宽度
let viewport = page.getViewport({scale: screen.availWidth / page.getViewport({scale: this.pdfScale}).width})
2、低端浏览器渲染报错environment lacks native support…
需要修改下引用pdfjs-dist的方式
之前是
const PDFJS = require("pdfjs-dist");
需要改成
const PDFJS = require("pdfjs-dist/es5/build/pdf");
参考
更多推荐
已为社区贡献2条内容
所有评论(0)