pdf的使用和兼容问题
1. 开始使用vue-pdf这个插件, 发现它只适用于页码小的文件, 文件大了容易卡顿奔溃 (建议小文件使用,比较方便)
2. 然后做优化, 在包裹pdf显示外层div添加滚动事件, 初始渲染的页数不要显示总页数,可以自己定义设置想要的页数如初始显示10页,显示少一些卡顿有效缓解, 监听滚动做分页功能。(这种方式在50页以内还行,再大了有些配置低点的机型扛不住,也会卡顿)
3. 因为文件上百页,没办法选择切换插件,选了pdfjs-dist, 这个是没有封装的,自己进行处理, 解决了上面的问题
4. 这里遇到的几个问题,
4.1 vue-pdf和pdfjs-dist引入会出现盖章不显示问题,解决方案:需注释依赖中的部分代码
if (data.fieldType === "Sig") {
// data.fieldValue = null;
// this.setFlags(_util.AnnotationFlag.HIDDEN);
}
4.2 vue-fdf 出现二次回显,填充内容不显示问题
//node_modules/vue-pdf/CMapReaderFactory.js
// .then 后面添加 加载完语言文件后清除缓存
delete require.cache[require.resolve('./buffer-loader!pdfjs-dist/cmaps/'+query.name+'.bcmap')]
4.3 部分文字不显示的问题
引入CMapReaderFactory
4.4 移动端放大缩小问题
这里引入了腾讯手势库 AlloyFinger
5. 示例demo
<template>
<section class="main">
<article ref="pdfContainer" class="content">
<div class="pdf_box" ref="pdfBoxDom">
<canvas
v-for="index in PDFPageCount"
v-bind:key="index"
:ref="'canvas_' + index"
:style="{ width: scale * pdfWidth + 'px' }"
></canvas>
</div>
</article>
<div v-show="isLoading" class="overlay_dialog">
<van-loading size="44" vertical> 加载中... </van-loading>
</div>
</section>
</template>
<script>
// import pdf from 'vue-pdf';
import AlloyFinger from 'alloyfinger';
// 解决部分文字不显示的问题
import CMapReaderFactory from 'vue-pdf/src/CMapReaderFactory.js';
const pdfjsLib = require('pdfjs-dist/es5/build/pdf');
const workerSrc = require('pdfjs-dist/es5/build/pdf.worker.entry.js');
// 防抖 callback 回调函数 ms 周期性执行回调间隔时间ms
function debounce(callback, ms) {
let timer, isScroll;
return function () {
if (isScroll) {
return;
}
isScroll = true;
timer && clearTimeout(timer);
timer = setTimeout(() => {
callback && callback();
isScroll = false;
timer = null;
}, ms);
};
}
export default {
name: 'TrustContract',
// components: { pdf },
data() {
return {
info: {},
isLoading: false,
scaleFlag: true, // 是否可缩放
PDFDocument: null, // PDF 文档类
PDFPageCount: 0, // PDF 文档总页数
pdfWidth: 0, // PDF 宽
pdfHeight: 0, // PDF 高
pageNumber: 1, // 当前加载的页码
scale: 1, // PDF 文档缩放倍数
oldscale: 1,
};
},
created() {
this.info = this.$route.query || {};
if (this.info.contractPath) {
pdfjsLib.GlobalWorkerOptions.workerSrc = workerSrc;
this.$nextTick(() => {
this.loadFile();
});
}
},
mounted() {
this.getData();
},
methods: {
loadFile() {
let url = window.customConfig.filePathPdf.url + this.info.contractPath;
this.isLoading = true;
pdfjsLib
.getDocument({ url, CMapReaderFactory })
.promise.then(
(PDF) => {
this.PDFPageCount = PDF.numPages;
this.PDFDocument = PDF;
this.$nextTick(() => {
// 重置元素为未读状态
Object.keys(this.$refs)
.filter((tmp) => /canvas.*_\d/.test(tmp))
.forEach((tmp) => {
this.$refs[tmp].isRead = false;
});
// 绑定滑动事件
this.$refs.pdfBoxDom.addEventListener(
'scroll',
debounce(this.contentScroll, 200),
true,
);
// 一次性加载10页
const loadPage = this.PDFPageCount > 5 ? 5 : this.PDFPageCount;
for (let i = 1; i <= loadPage; i++) {
this.pageNumber = i;
this.getPageAndRender();
}
this.isLoading = false;
});
},
(e) => (this.isLoading = false),
)
.catch((e) => (this.isLoading = false));
},
// 滑动展示PDF
contentScroll() {
const scrollTop = this.$refs.pdfBoxDom.scrollTop;
// 获取到下一个未加载的
const nextPage = this.pageNumber + 1;
const canvas = this.$refs['canvas_' + nextPage];
if (!canvas || (canvas && canvas.isRead)) {
return;
}
if (scrollTop > (this.pageNumber - 2) * this.pdfHeight * this.scale - 100) {
const nextCount = this.pageNumber + 5;
const loadPage = this.PDFPageCount > nextCount ? nextCount : this.PDFPageCount;
for (let i = nextPage; i <= loadPage; i++) {
this.pageNumber = i;
this.getPageAndRender();
}
}
},
// 加载PDF图片
getPageAndRender() {
// 超过总页数或已隐藏,则不再继续加载
if (this.pageNumber > this.PDFPageCount) {
return;
}
// 判断是否已加载过
const canvas = this.$refs['canvas_' + this.pageNumber];
if (canvas && !canvas.isRead) {
console.log('getPageAndRender---', this.pageNumber);
canvas.isRead = true;
// 获取当前页码PDF的属性并渲染到页面
this.PDFDocument.getPage(this.pageNumber)
.then(
(page) => {
// 设置视口的所需比例
const viewport = page.getViewport({ scale: 2 });
// PDF文件 viewport 成功才继续做渲染操作
const canvasHtml = canvas && canvas[0];
if (viewport && viewport.width && canvasHtml && canvasHtml.width) {
const _width = window.screen.availWidth;
// 设置画布宽高
canvasHtml.width = viewport.width;
canvasHtml.height = viewport.height;
// 设置缩放比例
this.scale = this.oldscale = _width / viewport.width;
console.log(this.scale, 'this.scale456');
// 储存
this.pdfWidth = viewport.width;
this.pdfHeight = viewport.height;
// 渲染PDF到页面
page.render({ canvasContext: canvasHtml.getContext('2d'), viewport: viewport });
}
},
(e) => (this.isLoading = false),
)
.catch((e) => (this.isLoading = false));
}
},
// 初始化手势缩放
getData() {
let that = this;
let pic = this.$refs.pdfContainer;
this.af = new AlloyFinger(pic, {
pinch(evt) {
// 避免误操作,过小过滤掉
let zoom = evt.zoom || 1;
if (zoom > 0.8 && zoom < 1.2) return false;
// 防抖
if (!that.scaleFlag) return false;
console.log(evt.zoom, '实现缩放');
that.scaleFlag = false;
setTimeout(() => {
that.scaleFlag = true;
}, 200);
if (zoom > 1) {
// 设置最大缩放
that.scale = that.scale + 0.1 < 1 ? that.scale + 0.1 : 1;
} else if (zoom < 1) {
// 设置最小缩放
that.scale = that.scale - 0.1 > that.oldscale ? that.scale - 0.1 : that.oldscale;
}
},
});
},
},
};
</script>
<style lang="less" scoped>
.pdf_box {
width: 100%;
height: calc(100vh - 44px);
overflow-y: scroll;
}
.overlay_dialog {
position: fixed;
top: 44px;
left: 0;
bottom: 77px;
z-index: 1;
width: 100%;
}
/deep/.van-loading {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
</style>