现在开始想写点东西来记录一下开发过程中爬的坑,一方面方便自己查看,也希望能帮到同样遇到此类问题的开发者。
pdfjs的setDocument 方式渲染页面快,适合大文件, 不需要自己渲染字体,那么如何在移动端实现手势动态缩放文档呢?下面贴出自己在vue项目中写的组件。
// src/components/pdf/pdf.js
<template>
<div class="pdf-view">
<div id="viewerContainer" ref="container">
<div id="viewer" class="pdfViewer"
@touchstart="touchstart"
@touchmove="touchmove"
@touchend="touchend"/>
</div>
</div>
</template>
<script>
import getPdfjsDist from '@/components/pdf/getPdfjsDist'
export default {
name: 'Pdf',
props: {
url: {
type: String,
default: ''
},
type: {
type: String,
default: 'svg'
},
pdfjsDistPath: {
type: String,
default: '../../../static'
},
DEFAULT_SCALE_DELTA:{
type:Number,
default:1.1
},
DEFAULT_SCALE_VALUE:{
type:String,
default:'auto'
},
MIN_SCALE:{
type:Number,
default:0.1
},
MAX_SCALE:{
type:Number,
default:10
}
},
data() {
return {
pdfViewer: null,
pdfLinkService: null,
currentScale: 'page-width',
loadingTask: null,
touchDistance:0,
previousPinchScale: 1,
startTime: 0,
startX:null,
startY:null,
moveX:null,
moveY:null,
eLen:0,
}
},
methods: {
onPagesInit({source}) {
source.currentScaleValue = this.currentScale
},
async pdfLibInit() {
let pdfjsLib = window.pdfjsLib;
let pdfjsViewer = window.pdfjsViewer
if (!pdfjsLib || !pdfjsViewer) {
try {
await getPdfjsDist(this.pdfjsDistPath)
this.CMAP_URL = `${this.pdfjsDistPath}/pdfjs-dist/cmaps/`
pdfjsLib = window.pdfjsLib;
pdfjsLib.GlobalWorkerOptions.workerSrc = `${this.pdfjsDistPath}/pdfjs-dist/es5/build/pdf.worker.js`
pdfjsViewer = window.pdfjsViewer
} catch (error) {
// console.log(error)
// pdfjs文件获取失败
return
}
}
const container = this.$refs.container
const eventBus = new pdfjsViewer.EventBus();
// (Optionally) enable hyperlinks within PDF files.
const pdfLinkService = new pdfjsViewer.PDFLinkService({
eventBus: eventBus,
});
this.pdfLinkService = pdfLinkService
const pdfViewer = new pdfjsViewer.PDFViewer({
container: container,
eventBus: eventBus,
linkService: pdfLinkService,
renderer: this.type,
textLayerMode: 0,
downloadManager: new pdfjsViewer.DownloadManager({}),
enableWebGL: true
});
this.pdfViewer = pdfViewer
pdfLinkService.setViewer(pdfViewer);
eventBus.on("pagesinit", this.onPagesInit);
},
_getDistance(xLen,yLen) {
return Math.sqrt(xLen * xLen + yLen * yLen);
},
touchstart(e){
this.startTime = this._getTime();
this.startX = e.touches[0].pageX;
this.startY = e.touches[0].pageY;
if(e.touches.length > 1) {
let point1 = e.touches[0];
let point2 = e.touches[1];
let xLen = Math.abs(point2.pageX - point1.pageX);
let yLen = Math.abs(point2.pageY - point1.pageY);
this.touchDistance = this._getDistance(xLen, yLen);
}
},
touchmove(e){
this.moveX = e.touches[0].pageX;
this.moveY = e.touches[0].pageY;
this.eLen =e.touches.length;
if(e.touches.length > 1) {
let xLen = Math.abs(e.touches[0].pageX - e.touches[1].pageX);
let yLen = Math.abs(e.touches[0].pageY - e.touches[1].pageY);
let touchDistance = this._getDistance(xLen,yLen);
if(this.touchDistance) {
let pinchScale = touchDistance / this.touchDistance;
this.previousPinchScale = pinchScale>1? pinchScale: 1;
}
}
},
_getTime(){
return new Date().getTime();
},
touchend(e){
let timestamp = this._getTime();
if(this.moveX !== null && Math.abs(this.moveX - this.startX) > 10 ||
this.moveY !== null && Math.abs(this.moveY - this.startY) > 10){
if(timestamp - this.startTime < 500 && this.eLen>=2) {//手指移动的位移要大于10像素并且手指和屏幕的接触时间要短于500毫秒
if(this.previousPinchScale > 1){
this.zoomIn();
}else{
this.zoomOut();
}
this.eLen = 0;
}
}
},
zoomIn() {
if (this.pdfViewer.isInPresentationMode) {
return;
}
var newScale = this.pdfViewer.currentScale;
if(newScale < this.MAX_SCALE){
newScale = (newScale * this.DEFAULT_SCALE_DELTA).toFixed(2);
newScale = Math.ceil(newScale * 10) / 10;
newScale = Math.min(this.MAX_SCALE, newScale);
}
this.pdfViewer.currentScaleValue = newScale;
},
zoomOut() {
if (this.pdfViewer.isInPresentationMode) {
return;
}
var newScale = this.pdfViewer.currentScale;
if(newScale > this.MIN_SCALE){
newScale = (newScale / this.DEFAULT_SCALE_DELTA).toFixed(2);
newScale = Math.floor(newScale * 10) / 10;
newScale = Math.max(this.MIN_SCALE, newScale);
}
this.pdfViewer.currentScaleValue = newScale;
},
zoomReset() {
if (this.pdfViewer.isInPresentationMode) {
return;
}
this.pdfViewer.currentScaleValue = this.DEFAULT_SCALE_VALUE;
},
renderPdf() {
if (!this.url) { return }
// Loading document.
if (this.pdfViewer === null || this.pdfLinkService === null) {
return
}
if (this.loadingTask !== null) {
this.loadingTask.destroy()
this.loadingTask = null
}
this.loadingTask = window.pdfjsLib.getDocument({
cMapUrl: this.CMAP_URL,
cMapPacked: true,
url: this.url,
});
return this.loadingTask.promise.then((pdfDocument) => {
if (pdfDocument.loadingTask.destroyed || !this.url) { return }
this.pdfViewer.setDocument(pdfDocument)
this.pdfLinkService.setDocument(pdfDocument, null);
this.loadingTask = null
}).catch(error => {
console.log(error)
});
}
},
mounted() {
this.pdfLibInit().then(() => {
this.renderPdf()
})
},
watch: {
url() {
// 如果存在pdfViewer则取消渲染
if(this.pdfViewer) {
this.pdfViewer._cancelRendering()
}
this.renderPdf()
}
}
}
</script>