Vue实现图片预览,侧边栏懒加载,不用任何插件,简单好用

实现样式

在这里插入图片描述

需求

实现PDF上传预览,并且不能下载

第一次实现:用vue-pdf,将上传的文件用base64传给前端展示
问题:

  1. 水印第一次加载有后面又没有了。
  2. 当上传大的pdf文件后,前端获取和渲染又长又慢,甚至不能用

修改实现模式

  1. 前端上传PDF,后端将PDF转化成一页一页的图片
  2. 前端根据page去获取一页一页的PDF图片,类似于百度文库

实现思路

配合后端实现思路

  1. 获取全部页数,先把侧边栏的元素画出来占个位置
  2. 获取已经看到的页数,没有默认1
  3. 渲染上次看到的页数,同时侧边栏滚动到相同的index位置,通过监听元素是否进入视口去获取base64图片
  4. 已经获取回来的图片不再去请求

主要难点是侧边栏懒加载和定位

 <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);
        }
      });
    },
  },
  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 = () => {
     
        canvas.width = image.width;
        canvas.height = image.height;
        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>

相关推荐

  1. Vue3实现图片

    2024-01-25 05:20:01       16 阅读
  2. Vue图片实现

    2024-01-25 05:20:01       9 阅读
  3. 前端图片

    2024-01-25 05:20:01       19 阅读
  4. Vue中使用v-viewer实现点击图片

    2024-01-25 05:20:01       11 阅读
  5. vue图片

    2024-01-25 05:20:01       13 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-01-25 05:20:01       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-01-25 05:20:01       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-01-25 05:20:01       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-01-25 05:20:01       20 阅读

热门阅读

  1. git 本地分支提交远程分支

    2024-01-25 05:20:01       36 阅读
  2. 并查集算法实现

    2024-01-25 05:20:01       34 阅读
  3. xpath注入漏洞靶场搭建记录

    2024-01-25 05:20:01       33 阅读
  4. 分支和循环语句

    2024-01-25 05:20:01       31 阅读
  5. docker 镜像打包,离线部署

    2024-01-25 05:20:01       37 阅读
  6. springboot切面怎么将参数修改后传给目标方法

    2024-01-25 05:20:01       35 阅读
  7. Golang 定时任务的几种实现方法

    2024-01-25 05:20:01       34 阅读
  8. C# 实现 Vigenere 密码

    2024-01-25 05:20:01       27 阅读