<template>
<div class="view">
<!-- <template v-for="item in pageNum" :key="item"> -->
<!-- :id="`pdf-canvas-${item}`" -->
<canvas
id="pdf-canvas"
class="pdf-page"
@touchstart="touchstart"
@touchmove="touchmove"
@touchend="touchend($event, 1)"
/>
<!-- @touchend="touchend($event, item)" -->
<!-- </template> -->
<div class="footer">
<Button
size="mini"
color="#006BE1"
type="primary"
@click="changeCurrentPage('previousPage')"
>
上一页
</Button>
<div class="pageNum">{{ currentPage }}/{{ pageNum }}</div>
<Button
size="mini"
color="#006BE1"
type="primary"
@click="changeCurrentPage('nextPage')"
>
下一页
</Button>
</div>
</div>
<!-- <div class="footer">
<Button color="#006BE1" type="primary" @click="downLoadPDF" class="btn">
下载文件
</Button>
</div> -->
</template>
<script setup lang="ts">
import { reactive, toRefs, nextTick, watchEffect, defineProps } from "vue";
//@ts-ignore
import * as pdfjs from "pdfjs-dist";
//@ts-ignore
import pdfjsWorker from "pdfjs-dist/build/pdf.worker.entry";
import { Toast, Button } from "vant";
// import { downloadFile } from "@/utils";
pdfjs.GlobalWorkerOptions.workerSrc = pdfjsWorker;
const props = defineProps({
url: { type: String, default: "" }, // pdf文件路径
});
const emit = defineEmits(["onRendered"]);
const state = reactive<any>({
currentPage: 1,
pageNum: 0,
pdfCtx: null,
touchDistance: 0,
previousPinchScale: 1,
startTime: 0,
startX: null,
startY: null,
moveX: null,
moveY: null,
eLen: 0,
width: 0,
height: 0,
});
const changeCurrentPage = (type: "nextPage" | "previousPage") => {
if (type === "nextPage") {
if (state.currentPage === state.pageNum) {
return;
} else {
state.currentPage++;
}
} else {
if (state.currentPage === 1) {
return;
} else {
state.currentPage--;
}
}
renderPdf(state.currentPage, 1);
};
const resolvePdf = (url: string) => {
const loadingTask = pdfjs.getDocument(url);
loadingTask.promise.then((pdf: any) => {
state.pdfCtx = pdf;
state.pageNum = pdf.numPages;
nextTick(() => {
renderPdf(1, 1);
});
});
};
const renderPdf = (num: number, scale: number) => {
state.pdfCtx.getPage(num).then((page: any) => {
// const canvas: any = document.getElementById(`pdf-canvas-${num}`);
const canvas: any = document.getElementById(`pdf-canvas`);
const ctx = canvas.getContext("2d");
// test
let dpr = window.devicePixelRatio || 1;
let bsr =
ctx.webkitBackingStorePixelRatio ||
ctx.mozBackingStorePixelRatio ||
ctx.msBackingStorePixelRatio ||
ctx.oBackingStorePixelRatio ||
ctx.backingStorePixelRatio ||
1;
let ratio = dpr / bsr;
let scalNum = scale || 1;
let viewport = page.getViewport({
scale: screen.availWidth / page.getViewport({ scale: 1 }).width,
});
canvas.width = viewport.width * ratio * scalNum;
canvas.height = viewport.height * ratio * scalNum;
state.width = viewport.width * ratio * scalNum;
state.height = viewport.height * ratio * scalNum;
canvas.style.width = viewport.width * scalNum + "px";
canvas.style.height = viewport.height * scalNum + "px";
let renderContext = {
//这里transform比较关键 保证根据手势缩放后的清晰度和等比例
transform: [ratio * scalNum, 0, 0, ratio * scalNum, 0, 0],
canvasContext: ctx,
viewport: viewport,
};
page.render(renderContext).promise.then(() => {
// 渲染水印
renderWatermark(num);
});
/**开始 */
// const viewport = page.getViewport({ scale: 1 });
// // 画布大小,默认值是width:300px,height:150px
// canvas.height = viewport.height;
// canvas.width = viewport.width;
// // 画布的dom大小, 设置移动端,宽度设置铺满整个屏幕
// const clientWidth = document.body.clientWidth;
// canvas.style.width = clientWidth + "px";
// // 根据pdf每页的宽高比例设置canvas的高度
// canvas.style.height =
// clientWidth * (viewport.height / viewport.width) + "px";
// page.render({
// canvasContext: ctx,
// viewport,
// });
/**结束 */
/**渲染一张即可 */
// if (num < state.pageNum) {
// renderPdf(num + 1, 1);
// } else {
emit("onRendered");
Toast.clear(); // 取消加载loading
// }
});
};
const _getDistance = (xLen: any, yLen: any) => {
return Math.sqrt(xLen * xLen + yLen * yLen);
};
const touchstart = (e: any) => {
state.startTime = _getTime();
console.log("e.touches", e.touches);
state.startX = e.touches[0].pageX;
state.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);
state.touchDistance = _getDistance(xLen, yLen);
}
};
const touchmove = (e: any) => {
state.moveX = e.touches[0].pageX;
state.moveY = e.touches[0].pageY;
state.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 = _getDistance(xLen, yLen);
if (state.touchDistance) {
let pinchScale = touchDistance / state.touchDistance;
state.previousPinchScale = pinchScale > 1 ? pinchScale : 1;
}
}
};
const _getTime = () => {
return new Date().getTime();
};
const touchend = (e: any, num: number) => {
let timestamp = _getTime();
if (
(state.moveX !== null && Math.abs(state.moveX - state.startX) > 10) ||
(state.moveY !== null && Math.abs(state.moveY - state.startY) > 10)
) {
if (timestamp - state.startTime < 500 && state.eLen >= 2) {
//手指移动的位移要大于10像素并且手指和屏幕的接触时间要短于500毫秒
renderPdf(num, state.previousPinchScale);
state.eLen = 0;
}
}
};
const initWatermark = () => {
let canvas = document.createElement("canvas");
canvas.width = 300;
canvas.height = 200;
const ctx = canvas.getContext("2d");
if (ctx) {
ctx.rotate((-18 * Math.PI) / 180);
ctx.scale(2, 2);
ctx.font = `18px Vedana`;
ctx.fillStyle = "rgba(200, 200, 200, .3)";
ctx.textAlign = "left";
ctx.textBaseline = "middle";
ctx.fillText("雷神大哥大", 50, 50);
}
return canvas;
};
const renderWatermark = (index: number) => {
// let canvas = document.querySelector(`#pdf-canvas-${index}`);
let canvas = document.querySelector(`#pdf-canvas`);
if (canvas) {
//@ts-ignore
let ctx = canvas.getContext("2d");
// 平铺水印
let pattern = ctx.createPattern(initWatermark(), "repeat");
ctx.rect(0, 0, state.width, state.height);
ctx.fillStyle = pattern;
ctx.fill();
}
};
watchEffect(() => {
if (props.url) {
// 展示加载loading
Toast.loading({
message: "加载中...",
overlay: true,
forbidClick: true,
duration: 0,
});
resolvePdf(props.url);
}
});
const { pageNum, pdfCtx, currentPage } = toRefs(state);
</script>
<style scoped>
/* .view {
padding-bottom: 1.5rem;
}
.footer {
position: fixed;
bottom: 0;
width: 100%;
padding: 0.16rem 0.4rem 0.6rem;
display: flex;
align-items: center;
height: 1.5rem;
box-shadow: 0px -1px 0px rgba(49, 69, 106, 0.164254);
background-color: #fff;
}
.btn {
width: 100%;
}
.van-button {
border-radius: 0.1rem;
} */
.footer {
position: fixed;
bottom: 0;
width: 100%;
padding: 0.16rem 0.4rem 0.8rem;
display: flex;
align-items: center;
height: 1.4rem;
background-color: #fff;
justify-content: center;
}
.pageNum {
margin: 0 12px;
}
</style>
设置pdf的放大缩小
于 2022-03-17 17:57:32 首次发布