赞
踩

实现PDF上传预览,并且不能下载
第一次实现:用vue-pdf,将上传的文件用base64传给前端展示
问题:
- 水印第一次加载有后面又没有了。
- 当上传大的pdf文件后,前端获取和渲染又长又慢,甚至不能用
配合后端实现思路
主要重点难点是侧边栏懒加载、定位、等比例展示图片
<div class="pdf-viewer"> <div class="pdf-main"> <canvas id="pdf-view"></canvas> </div> <div class="pdf-list" :class="{ collapse: collapse }"> <div class="pdf-item" :class="{ active: currentPage === index }" v-for="index in pageTotalNum" :key="index" @click="changePage(index)" :data-index="index" > <img :src="imgList[index - 1]" alt="" /> </div> </div> </div> <script> let observer = null; export default { name: "PDFView", data() { return { currentPage: 1, //当前页数 pageTotalNum: 1, //总页数 imgList: [], //base64图片列表 updateTimer: null }; }, watch: { /** * @description 监听当前页变化 滚动列表到顶部 */ currentPage() { this.$nextTick(() => { const activeEl = document.querySelector(".pdf-list .active"); if (activeEl) { document.querySelector(".pdf-list").scrollTo({ top: activeEl.offsetTop - 20, behavior: "smooth", }); // 解决进来会请求当前页数 前面所有图片 setTimeout(() => { if (observer) { observer.disconnect(); } this.isEnter(); }, 500); } // 切换页面 将查看区域滚动到最上面 const mainEl = document.querySelector(".pdf-main"); mainEl.scrollTo({ top: 0, }); }); }, }, mounted() { this.getPageTotal(); }, beforeDestroy() { if (observer) { observer.disconnect(); } }, methods: { /** * @description 获取pdf总页数 */ getPageTotal() { const params = { id: this.$route.query.id, }; apiGetViewPdfPageTotal(params).then((response) => { this.pageTotalNum = response.data; this.updateStudy(true); }); }, /** * @description 切换当前页 */ changePage(index) { this.currentPage = index; this.updateStudy(); if (this.imgList[index - 1]) { this.drawImage(this.imgList[index - 1]); } else { this.getPdf(); } }, /** * @description 上一页 */ prePage() { let page = this.currentPage; if (page !== 1) { page = page > 1 ? page - 1 : this.pageTotalNum; this.currentPage = page; this.updateStudy(); if (this.imgList[page - 1]) { this.drawImage(this.imgList[page - 1]); } else { this.getPdf(); } } }, /** * @description 下一页 */ nextPage() { let page = this.currentPage; if (page !== this.pageTotalNum) { page = page < this.pageTotalNum ? page + 1 : 1; this.currentPage = page; this.updateStudy(); if (this.imgList[page - 1]) { this.drawImage(this.imgList[page - 1]); } else { this.getPdf(); } } }, /** * @description 更新学习 flag=true第一次进入 */ updateStudy(flag = false) { const params = { courseId: this.$route.query.id, pageRate: this.currentPage, flag, totalPageRate: this.pageTotalNum, }; apiUpdateStudy(params) .then((response) => { this.currentPage = response.data.pageRate; if (flag) { this.updateTimer = setInterval(() => { this.updateStudy(); }, 1000 * 10); } if (flag) { this.getPdf(); // 解决第一页进来不请求的问题,一页大概能展示4-5张 if (this.currentPage < 5) { this.isEnter(); } } }) }, /** * @description 查看资料 */ getPdf() { const params = { id: this.$route.query.id, page: this.currentPage, }; apiGetPdf(params).then((response) => { let base64 = "data:image/png;base64," + response.data; this.drawImage(base64); }); }, /** * @description 将base64图片 画到canvas上 */ drawImage(base64) { const canvas = document.getElementById("pdf-view"); const context = canvas.getContext("2d"); const image = new Image(); image.src = base64; image.onload = () => { const proportion = image.width / image.height; // 获取style设置width:100% 的canvas宽度 const canvasWidth = canvas.offsetWidth; // 图片宽度与canvas宽度比例 const canvasWidthProportion = image.width / canvasWidth; // canvas宽度设置为宽度 canvas.width = image.width; // 根据图片比例和宽度比例计算出canvas高度 canvas.height = (canvasWidth / proportion) * canvasWidthProportion; context.drawImage(image, 0, 0); }; }, /** * @description 监听元素进入视口 */ isEnter() { observer = new IntersectionObserver((entries) => { entries.forEach((entry) => { const target = entry.target; const index = target.dataset.index; if (entry.isIntersecting) { if (!this.imgList[index - 1]) { this.getImgList(index); } } else { // console.log("元素离开视口", index); } }); }); this.$nextTick(() => { //将所有侧边栏的元素进行监听 const els = document.querySelectorAll(".pdf-item"); Array.from(els).forEach((el) => { observer.observe(el); }); }); }, /** * @description 滚动获取图片 */ getImgList(index) { const params = { id: this.$route.query.id, page: index, }; apiGetPdf(params).then((response) => { let base64 = "data:image/png;base64," + response.data; this.imgList[index - 1] = base64; // 解决请求回来页面没更新的问题 this.$forceUpdate(); }); }, }, }; </script> <style lang="scss" scoped> .pdf-container { width: 100%; height: 100%; color: #999; } .pdf-viewer { width: 100%; height: calc(100vh - 50px - 30px - 60px - 6px); position: relative; display: flex; } .pdf-list { width: 240px; overflow-y: auto; display: flex; flex-direction: column; padding: 20px; background: #000; box-sizing: border-box; // transition: all 0.3s ease-in-out; border-left: 1px solid #999; &::-webkit-scrollbar { width: 0px; } .pdf-item { height: 183px; min-height: 183px; display: inline-flex; justify-content: center; align-items: center; cursor: pointer; overflow: hidden; &:hover { ::v-deep img { transition: all 0.5s ease-in-out; transform: scale(1.1); } } &.active { box-shadow: 0px 0px 0px 4px #e6a23c; } &:not(:last-child) { margin-bottom: 10px; } img { pointer-events: none; width: 100%; // height: 100%; } } &.collapse { width: 0; padding: 0; } } .pdf-main { flex: 1; // width: 100%; // height: 100%; overflow-y: auto; background: #000; position: relative; padding: 10px 0; &::-webkit-scrollbar { width: 0px; } } .handle-btn { background: #000; display: flex; font-size: 12px; position: relative; height: 60px; padding: 0 6px; border-bottom: 1px solid #999; .right { width: 240px; display: flex; align-items: center; justify-content: flex-end; font-size: 32px; } .main { flex: 1; display: flex; align-items: center; justify-content: center; font-size: 32px; margin-left: 250px; .pagination { display: flex; align-items: center; margin: 0 10px; .pagination-info { font-size: 14px; margin: 0 8px; } } .zoom { display: flex; align-items: center; margin: 0 10px; .scale { font-size: 14px; margin: 0 8px; } } } .tips { color: #e6a23c; font-size: 12px; } .start-test { display: flex; align-items: center; } .time { position: absolute; left: 6px; top: 50%; transform: translateY(-50%); > span { display: inline-block; margin-left: 10px; } } } i { cursor: pointer; &:hover { color: #fff; } } #pdf-view { width: 100%; // height: 100%; padding: 10px; } </style>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。