Vue后台管理系统封装vue-pdf组件切换到下一个数组列表数据显示的功能、解决组件获取到url不能二次渲染的问题

发布于:2022-12-24 ⋅ 阅读:(612) ⋅ 点赞:(0)

目录

一、封装的pdf.vue 添加了数据加载loading的效果

二、基于vue封装的pdf组件不能去监听获取到的新url二次去渲染,由于我这边的业务、pdf文件超过100M左右、如果全部去获取到数组里面的数据全部加载回来再本地再次渲染、导致会内存溢出

三、重构之后的pdf渲染组件、通过请求全部的数组数据的url加载到本地、再去通过index对比去渲染、这个逻辑如果pdf文件不大、完全是没问题、考虑到pdf文件过大这个逻辑并不适用

四、理清思路后其实这个问题主要还是这个pdf组件的问题、如果更换其他组件很多项目逻辑要更改、考虑到这一点、我们可以去通过切换到下一个数组数据的时候去本地存储下一件的id、再去刷新整个页面的DOM、实现每次请求都只会请求一个url、数据加载就会快很多

总结、这样就可以规避组件不能二次渲染的问题、无论pdf文件有多大、浏览器只加载一个url时间不会太长、代码没有标注、可以私信我沟通


一、封装的pdf.vue 添加了数据加载loading的效果

<template>
  <div class="pdf-viewer-inner">
    <pdf
      v-for="i in numPages"
      :key="i"
      :src="src"
      @loaded="loading"
      :page="i"
      @error="pdferr"
    />
    <div v-if="loadingStatus" class="loading-title">
      <i class="el-icon-loading"></i>加载中......
    </div>
  </div>
</template>

<script>
import pdf from "vue-pdf";

export default {
  components: {
    pdf,
  },
  props: {
    url: {
      type: String,
      default: "",
    },
  },
  data() {
    return {
      src: null,
      numPages: undefined,
      nowLoadingNum: 0,
      loadingStatus: true,
    };
  },
  mounted() {
    this.loadingTask(this.url);
  },
  methods: {
    loadingTask: function (val) {
      if (this.src === val) {
        return;
      }
      this.src = pdf.createLoadingTask(val);
      this.src.promise
        .then((pdf) => {
          this.numPages = pdf.numPages;
          this.loadingStatus = true;
        })
        .catch((err) => {
          console.error("pdf 加载失败", err);
        });
    },

    loading: function (val) {
      this.nowLoadingNum += 1;
      if (
        !!this.loadingStatus &&
        this.loadingStatus.close &&
        this.nowLoadingNum >= this.numPages &&
        typeof this.loadingStatus.close === "function"
      ) {
        this.loading.close();
        this.loadingStatus = false;
      }
    },
    pdferr: function (err) {
      if (err) {
        this.$message.error("加载失败,请重新刷新加载!");
        console.log(err, "err");
      }
    },
  },
};
</script>
<style lang="scss">
.pdf-viewer-inner {
  width: 100%;
  height: 100%;
  .pdf {
    // width
    height: 100%;
  }

  .loading-title {
    position: fixed;
    color: #fff;
    left: 50%;
  }
}
</style>

二、基于vue封装的pdf组件不能去监听获取到的新url二次去渲染,由于我这边的业务、pdf文件超过100M左右、如果全部去获取到数组里面的数据全部加载回来再本地再次渲染、导致会内存溢出

我一开始实现的第一种方法,我重构之前的逻辑、通过去请求全部数据回来再去判断渲染、不过这也会直接导致如果pdf文件过大、浏览器加载会内存溢出、附上代码

未重构之前的代码实现通过获取数组里面的数据去循环对比,获取到当前对应的id切换到下一个数组数据再去请求下一个的id值去切换、但是这样能获取到url并不能渲染 新的pdf

<template>
  <div id="pdf-viewer-wrapper">
    <div class="tools">
      <div class="left" v-if="singleArchivesFormId">
        <span @click="prePage"><i class="el-icon-arrow-left"></i>上一件</span
        ><span @click="nextPage"
          >下一件<i class="el-icon-arrow-right"></i
        ></span>
      </div>
      <div class="mid">{{ fileName }}</div>
      <div class="right">
        <span @click="enlarge(type)" class="el-icon-plus"></span>
        <span>{{ parseInt(type === 1 ? imageScal : pdfScal) + "%" }}</span>
        <span @click="narrow(type)" class="el-icon-minus"></span>
      </div>
    </div>
    <div v-if="type === 1" id="img-viewer">
      <img id="img-viewer2" :src="url" alt @error="myFunction" />
      <div class="mask" />
    </div>
    <div v-if="type === 2" id="pdf-viewer">
      <myPdf id="pdf-viewer2" :url="url" :page="pageNum" />
    </div>
    <div v-if="type === 3 && showVideo" class="video-viewer">
      <video-player
        ref="videoPlayer"
        class="video-player vjs-custom-skin"
        :playsinline="true"
        :options="playerOptions"
        @error="myFunction"
      />
    </div>
    <div v-if="type === 4" class="video-viewer">
      <audio :src="url" controls @error="myFunction">
        <source />
        您的浏览器不支持 audio 元素。
      </audio>
    </div>
  </div>
</template>
<script>
// import pdf from "vue-pdf";
import myPdf from "@/views/fileViewer/pdf";
import { videoPlayer } from "vue-video-player";
import "video.js/dist/video-js.css";
import {
  getSingleVolumeAttachmentDetail,
  getSingleVolumeAttachment,
} from "@/api/archivesManagement/singleVolumeMaterial";
import { len } from "zrender/lib/core/vector";
export default {
  name: "Home",
  components: {
    myPdf,
    videoPlayer,
  },
  data() {
    return {
      url: "",
      pageNum: 1,
      pageTotalNum: 1,
      pageRotate: 0,
      // 加载进度
      loadedRatio: 0,
      curPageNum: 0,
      numPages: null, // pdf 总页数
      id: null,
      fileName: null,
      fileType: "image%2Fjpeg",
      showVideo: false,
      singleArchivesFormId: null,
      current: null,
      scal: "50",
      currentStatus: false,
      imageScal: 50,
      pdfScal: 50,
      loading: false,
    };
  },
  computed: {
    type() {
      if (
        this.fileType === "image%2Fpng" ||
        this.fileType === "image%2Fjpeg" ||
        this.fileType === "image/png" ||
        this.fileType === "image/jpeg"
      ) {
        return 1;
      } else if (
        this.fileType === "application%2Fpdf" ||
        this.fileType === "application/pdf"
      ) {
        return 2;
      } else if (
        this.fileType === "video%2Fmp4" ||
        this.fileType === "video/mp4"
      ) {
        return 3;
      } else if (
        this.fileType === "audio%2Fmpeg" ||
        this.fileType === "audio/mpeg"
      ) {
        return 4;
      }
      return 5;
    },
    playerOptions() {
      console.log(this.url);
      return {
        playbackRates: [0.7, 1.0, 1.5, 2.0], // 播放速度
        autoplay: false, // 如果true,浏览器准备好时开始回放。
        muted: false, // 默认情况下将会消除任何音频。
        loop: false, // 导致视频一结束就重新开始。
        preload: "auto", // 建议浏览器在<video>加载元素后是否应该开始下载视频数据。auto浏览器选择最佳行为,立即开始加载视频(如果浏览器支持)
        language: "zh-CN",
        aspectRatio: "16:9", // 将播放器置于流畅模式,并在计算播放器的动态大小时使用该值。值应该代表一个比例 - 用冒号分隔的两个数字(例如"16:9"或"4:3")
        fluid: true, // 当true时,Video.js player将拥有流体大小。换句话说,它将按比例缩放以适应其容器。
        sources: [
          {
            src: this.url, // 路径
            type: "video/mp4", // 类型
          },
        ],
        // poster: "../../static/images/test.jpg", //你的封面地址
        // width: document.documentElement.clientWidth,
        notSupportedMessage: "此视频暂无法播放,请稍后再试", // 允许覆盖Video.js无法播放媒体源时显示的默认信息。
        controlBar: {
          timeDivider: true,
          durationDisplay: true,
          remainingTimeDisplay: false,
          fullscreenToggle: true, // 全屏按钮
        },
      };
    },
  },
  mounted: function () {
    this.getId();
    // console.log(this);
  },
  methods: {
    myFunction(_err) {
      // console.log(err);
      if (this.url.indexOf("www.gdart.site") > -1) {
        this.$message.warning("旧【粤艺研管理系统】丢失该文件,无法读取");
      }
    },
    getSingleVolumeAttachment(current) {
      this.loading = true;
      getSingleVolumeAttachment({
        singleVolumeId: this.singleArchivesFormId,
        current: current,
        size: 50,
      }).then((res) => {
        this.loading = false;
        this.singleArchivesFileList = res.data.records;
      });
    },
    getId() {
      document.oncontextmenu = function () {
        return false;
      };
      if (this.$route.query && this.$route.query.id) {
        this.id = Number(this.$route.query.id);
      }
      if (this.$route.query && this.$route.query.singleArchivesFormId) {
        this.singleArchivesFormId = this.$route.query?.singleArchivesFormId;
        this.current = this.$route.query?.current;
        this.getSingleVolumeAttachment(this.current);
      }
      this.getSingleVolumeAttachmentDetail(this.id);
    },
    // 上一件函数,
    prePage() {
      this.singleArchivesFileList.forEach((item, index) => {
        if (item.id === this.id) {
          const fileId = this.singleArchivesFileList[index - 1]?.id;
          if (fileId) {
            this.getSingleVolumeAttachmentDetail(fileId);
          } else {
            return this.$message.warning("已到最前一件");
          }
        }
      });
    },
    // 下一件函数
    nextPage() {
      this.singleArchivesFileList.forEach((item, index) => {
        if (item.id === this.id) {
          const fileId = this.singleArchivesFileList[index + 1]?.id;
          if (fileId) {
            this.getSingleVolumeAttachmentDetail(fileId);
          } else {
            return this.$message.warning("已到最后一件");
          }
        }
      });
    },
    // 页面顺时针翻转90度。
    clock() {
      this.id;
      this.pageRotate += 90;
    },
    // 页面逆时针翻转90度。
    counterClock() {
      this.pageRotate -= 90;
    },
    // 页面加载回调函数,其中e为当前页数
    pageLoaded(e) {
      this.curPageNum = e;
    },
    // 其他的一些回调函数。
    pdfError(error) {
      console.error(error);
    },
    // 放大
    enlarge(type) {
      this.$nextTick(() => {
        // imageWrapper 获取元素
        const imageWrapper = document.getElementById(
          type === 1 ? "img-viewer" : "pdf-viewer"
        );
        if (type === 1) {
          this.imageScal = (parseFloat(this.imageScal) + 10).toFixed(3);
          imageWrapper.style.width = this.imageScal + "%";
        } else {
          this.pdfScal = (parseFloat(this.pdfScal) + 10).toFixed(3);
          imageWrapper.style.width = this.pdfScal + "%";
        }
      });
    },
    // 缩小
    narrow(type) {
      this.$nextTick(() => {
        // imageWrapper 获取元素
        const imageWrapper = document.getElementById(
          type === 1 ? "img-viewer" : "pdf-viewer"
        );
        if (type === 1) {
          this.imageScal = (parseFloat(this.imageScal) - 10).toFixed(3);
          imageWrapper.style.width = this.imageScal + "%";
        } else {
          this.pdfScal = (parseFloat(this.pdfScal) - 10).toFixed(3);
          imageWrapper.style.width = this.pdfScal + "%";
        }
      });
    },

    getSingleVolumeAttachmentDetail(id) {
      this.loading = true;
      getSingleVolumeAttachmentDetail({ id: id }).then((res) => {
        this.loading = false;
        this.url =
          res.data.filePath.indexOf("https://www.gdart.site/resources/") > -1
            ? res.data.filePath
            : "https://art-archive.oss-cn-shenzhen.aliyuncs.com/" +
              res.data.filePath;
        console.log(this.url);
        this.id = id;
        this.fileName = res.data.fileName;
        this.fileType = res.data.fileType;
        this.showVideo = true;
      });
    },
  },
};
</script>
<style lang="scss">
#pdf-viewer-wrapper {
  position: relative;
  display: flex;
  justify-content: center;
  flex-direction: column;
  align-items: center;
  background: #434242;
  min-height: 100%;

  .tools {
    display: flex;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    width: 100%;
    height: 50px;
    line-height: 50px;
    justify-content: center;
    z-index: 99;
    background: #434242;
    border-bottom: 2px solid #fff;
    color: #fff;
    font-size: 18px;

    .left {
      margin-right: 38%;
      position: absolute;
      display: flex;
      align-items: center;

      i {
        display: flex;
        font-size: 24px;
        padding-top: 13px;
      }

      span {
        margin-right: 50px;
        cursor: pointer;
        display: flex;
        justify-content: space-between;
      }
    }

    .right {
      position: absolute;
      margin-left: 38%;
      span {
        margin-right: 50px;
        cursor: pointer;
      }
    }
  }

  #pdf-viewer {
    width: 50%;
    height: 80%;
    // padding-top: 50px;
    .pdf {
      // width
      height: 100%;
    }
  }

  .video-viewer {
    padding-top: 50px;
    height: 100%;
    width: 100%;
    display: flex;
    justify-content: center;
    align-items: center;

    .video-player {
      width: 80%;
      height: 80%;
    }
  }

  #img-viewer {
    position: relative;
    height: 100%;
    width: 100%;
    display: flex;
    justify-content: center;

    img {
      height: 50%;
      width: 50%;
      object-fit: cover;
    }

    .mask {
      position: absolute;
      left: 0;
      right: 0;
      top: 0;
      bottom: 0;
    }
  }

  .vjs-big-play-button {
    bottom: 10px !important;
    top: unset;
    right: 20px;
    left: unset;
  }
}
</style>

三、重构之后的pdf渲染组件、通过请求全部的数组数据的url加载到本地、再去通过index对比去渲染、这个逻辑如果pdf文件不大、完全是没问题、考虑到pdf文件过大这个逻辑并不适用

<template>
  <div id="pdf-viewer-wrapper">
    <div class="tools">
      <div v-if="singleArchivesFormId" class="left">
        <span @click="prePage"><i class="el-icon-arrow-left" />上一件</span
        ><span @click="nextPage">下一件<i class="el-icon-arrow-right" /></span>
      </div>
      <div class="mid">
        {{
          singleArchivesFileList.length - 1 >= nowIndex
            ? singleArchivesFileList[nowIndex].fileName
            : ""
        }}
      </div>
      <div class="right">
        <span class="el-icon-plus" @click="enlarge(type)" />
        <span>{{
          parseInt(
            getItemId(singleArchivesFileList[nowIndex]) === "img-viewer"
              ? imageScal
              : pdfScal
          ) + "%"
        }}</span>
        <span class="el-icon-minus" @click="narrow(type)" />
      </div>
    </div>

    <div
      v-for="(item, index) in singleArchivesFileList"
      v-show="index === nowIndex"
      :id="getItemId(item) + '-' + index"
      :key="item.id"
      :class="getItemClass(item)"
    >
      <!-- 图片 -->
      <img
        v-if="getItemId(item) === 'img-viewer'"
        id="img-viewer2"
        :src="getItemUrl(item)"
        alt
        @error="myFunction"
      />
      <div v-if="getItemId(item) === 'img-viewer'" class="mask" />
      <!-- pdf -->
      <myPdf v-if="getItemId(item) === 'pdf-viewer'" :url="getItemUrl(item)" />
      <!-- video -->
      <video-player
        v-if="getItemId(item) === 'video-viewer'"
        ref="videoPlayer"
        class="video-player vjs-custom-skin"
        :playsinline="true"
        :options="getViedoOptions(item)"
        @error="myFunction"
      />
      <!-- audio -->
      <audio
        v-if="getItemId(item) === 4"
        :src="getItemUrl(item)"
        controls
        @error="myFunction"
      >
        <source />
        您的浏览器不支持 audio 元素。
      </audio>
    </div>
  </div>
</template>
<script>
// import pdf from "vue-pdf";
import myPdf from "@/views/fileViewer/pdf";
import { videoPlayer } from "vue-video-player";
import "video.js/dist/video-js.css";
import {
  getSingleVolumeAttachmentDetail,
  getSingleVolumeAttachment,
} from "@/api/archivesManagement/singleVolumeMaterial";
export default {
  name: "Home",
  components: {
    myPdf,
    videoPlayer,
  },
  data() {
    return {
      url: "",
      pageNum: 1,
      pageTotalNum: 1,
      pageRotate: 0,
      // 加载进度
      loadedRatio: 0,
      curPageNum: 0,
      numPages: null, // pdf 总页数
      id: null,
      fileName: null,
      fileType: "image%2Fjpeg",
      showVideo: false,
      singleArchivesFormId: null,
      current: null,
      scal: "50",
      currentStatus: false,
      imageScal: 100,
      pdfScal: 50,
      singleArchivesFileList: [],
      nowIndex: 0,
      isType: null,
    };
  },
  computed: {
    type() {
      if (
        this.fileType === "image%2Fpng" ||
        this.fileType === "image%2Fjpeg" ||
        this.fileType === "image/png" ||
        this.fileType === "image/jpeg"
      ) {
        return 1;
      } else if (
        this.fileType === "application%2Fpdf" ||
        this.fileType === "application/pdf"
      ) {
        return 2;
      } else if (
        this.fileType === "video%2Fmp4" ||
        this.fileType === "video/mp4"
      ) {
        return 3;
      } else if (
        this.fileType === "audio%2Fmpeg" ||
        this.fileType === "audio/mpeg"
      ) {
        return 4;
      }
      return 5;
    },
    playerOptions() {
      return {
        playbackRates: [0.7, 1.0, 1.5, 2.0], // 播放速度
        autoplay: false, // 如果true,浏览器准备好时开始回放。
        muted: false, // 默认情况下将会消除任何音频。
        loop: false, // 导致视频一结束就重新开始。
        preload: "auto", // 建议浏览器在<video>加载元素后是否应该开始下载视频数据。auto浏览器选择最佳行为,立即开始加载视频(如果浏览器支持)
        language: "zh-CN",
        aspectRatio: "16:9", // 将播放器置于流畅模式,并在计算播放器的动态大小时使用该值。值应该代表一个比例 - 用冒号分隔的两个数字(例如"16:9"或"4:3")
        fluid: true, // 当true时,Video.js player将拥有流体大小。换句话说,它将按比例缩放以适应其容器。
        sources: [
          {
            src: this.url, // 路径
            type: "video/mp4", // 类型
          },
        ],
        // poster: "../../static/images/test.jpg", //你的封面地址
        // width: document.documentElement.clientWidth,
        notSupportedMessage: "此视频暂无法播放,请稍后再试", // 允许覆盖Video.js无法播放媒体源时显示的默认信息。
        controlBar: {
          timeDivider: true,
          durationDisplay: true,
          remainingTimeDisplay: false,
          fullscreenToggle: true, // 全屏按钮
        },
      };
    },
  },
  mounted: function () {
    this.getId();
    // console.log(this);
  },
  methods: {
    getItemId(item) {
      if (!item) return;
      if (
        item.fileType === "image%2Fpng" ||
        item.fileType === "image%2Fjpeg" ||
        item.fileType === "image/png" ||
        item.fileType === "image/jpeg"
      ) {
        return "img-viewer";
      } else if (
        item.fileType === "application%2Fpdf" ||
        item.fileType === "application/pdf"
      ) {
        return "pdf-viewer";
      } else if (
        item.fileType === "video%2Fmp4" ||
        item.fileType === "video/mp4"
      ) {
        return "video-viewer";
      } else if (
        item.fileType === "audio%2Fmpeg" ||
        item.fileType === "audio/mpeg"
      ) {
        return 4;
      }
      return 5;
    },
    getItemUrl(item) {
      console.log(item);
      
      return item.filePath.indexOf("https://www.gdart.site/resources/") > -1
        ? item.filePath
        : "https://art-archive.oss-cn-shenzhen.aliyuncs.com/" + item.filePath;
    },
    getViedoOptions(item) {
      console.log(item);
      return {
        playbackRates: [0.7, 1.0, 1.5, 2.0], // 播放速度
        autoplay: false, // 如果true,浏览器准备好时开始回放。
        muted: false, // 默认情况下将会消除任何音频。
        loop: false, // 导致视频一结束就重新开始。
        preload: "auto", // 建议浏览器在<video>加载元素后是否应该开始下载视频数据。auto浏览器选择最佳行为,立即开始加载视频(如果浏览器支持)
        language: "zh-CN",
        aspectRatio: "16:9", // 将播放器置于流畅模式,并在计算播放器的动态大小时使用该值。值应该代表一个比例 - 用冒号分隔的两个数字(例如"16:9"或"4:3")
        fluid: true, // 当true时,Video.js player将拥有流体大小。换句话说,它将按比例缩放以适应其容器。
        sources: [
          {
            src: this.getItemUrl(item), // 路径
            type: "video/mp4", // 类型
          },
        ],
        // poster: "../../static/images/test.jpg", //你的封面地址
        // width: document.documentElement.clientWidth,
        notSupportedMessage: "此视频暂无法播放,请稍后再试", // 允许覆盖Video.js无法播放媒体源时显示的默认信息。
        controlBar: {
          timeDivider: true,
          durationDisplay: true,
          remainingTimeDisplay: false,
          fullscreenToggle: true, // 全屏按钮
        },
      };
    },
    getItemClass(item) {
      return this.getItemId(item);
    },
    myFunction(_err) {
      // console.log(err);
      if (this.url.indexOf("www.gdart.site") > -1) {
        this.$message.warning("旧【粤艺研管理系统】丢失该文件,无法读取");
      }
    },
    getSingleVolumeAttachment(current) {
      getSingleVolumeAttachment({
        singleVolumeId: this.singleArchivesFormId,
        current: current,
        size: 50,
      }).then((res) => {
        this.singleArchivesFileList = res.data.records;
        this.singleArchivesFileList.forEach((item, index) => {
          if (item.id === this.id) {
            this.nowIndex = index;
          }
        });
        console.log(this.singleArchivesFileList);
      });
    },
    getId() {
      document.oncontextmenu = function () {
        return false;
      };
      if (this.$route.query && this.$route.query.id) {
        this.id = Number(this.$route.query.id);
      }
      if (this.$route.query && this.$route.query.singleArchivesFormId) {
        this.singleArchivesFormId = this.$route.query?.singleArchivesFormId;
        this.current = this.$route.query?.current;
        this.getSingleVolumeAttachment(this.current);
      }
      if (this.$route.query && this.$route.query.isType) {
        this.isType = Number(this.$route.query.isType);
        if (this.isType === 3 || this.isType === 4) {
          console.log("333333333");
          this.getSingleVolumeAttachmentDetail(this.id);
        }
      }
    },
    // 上一件函数,
    prePage() {
      if (this.nowIndex <= 0) {
        return this.$message.warning("已到最前一件");
      } else {
        this.nowIndex -= 1;
      }
    },
    // 下一件函数
    nextPage() {
      console.log(this.nowIndex, "11111");
      if (this.nowIndex >= this.singleArchivesFileList.length - 1) {
        return this.$message.warning("已到最后一件");
      } else {
        this.nowIndex += 1;
      }
    },
    // 页面顺时针翻转90度。
    clock() {
      this.id;
      this.pageRotate += 90;
    },
    // 页面逆时针翻转90度。
    counterClock() {
      this.pageRotate -= 90;
    },
    // 页面加载回调函数,其中e为当前页数
    pageLoaded(e) {
      this.curPageNum = e;
    },
    // 其他的一些回调函数。
    pdfError(error) {
      console.error(error);
    },
    // 放大
    enlarge(type) {
      this.$nextTick(() => {
        const Item = this.singleArchivesFileList[this.nowIndex];
        // imageWrapper 获取元素
        const idStr = this.getItemId(Item);
        // dom id arr
        const arr = [`img-viewer`, `pdf-viewer`];
        // is get dom
        const id = arr.includes(idStr) ? idStr : null;
        if (!id) return false;
        const imageWrapper = document.getElementById(id + "-" + this.nowIndex);

        if (idStr === "img-viewer") {
          this.imageScal = (parseFloat(this.imageScal) + 10).toFixed(3);
          imageWrapper.style.width = this.imageScal + "%";
        } else {
          this.pdfScal = (parseFloat(this.pdfScal) + 10).toFixed(3);
          imageWrapper.style.width = this.pdfScal + "%";
        }
      });
    },
    // 缩小
    narrow(type) {
      this.$nextTick(() => {
        const Item = this.singleArchivesFileList[this.nowIndex];
        // imageWrapper 获取元素
        const idStr = this.getItemId(Item);
        // dom id arr
        const arr = [`img-viewer`, `pdf-viewer`];
        // is get dom
        const id = arr.includes(idStr) ? idStr : null;
        if (!id) return false;
        const imageWrapper = document.getElementById(id + "-" + this.nowIndex);
        if (idStr === "img-viewer") {
          this.imageScal = (parseFloat(this.imageScal) - 10).toFixed(3);
          imageWrapper.style.width = this.imageScal + "%";
        } else {
          this.pdfScal = (parseFloat(this.pdfScal) - 10).toFixed(3);
          imageWrapper.style.width = this.pdfScal + "%";
        }
      });
    },
    getSingleVolumeAttachmentDetail(id) {
      getSingleVolumeAttachmentDetail({ id: id }).then((res) => {
        console.log(res, "res");
        this.singleArchivesFileList = [res.data];
      });
    },
  },
};
</script>
<style lang="scss">
#pdf-viewer-wrapper {
  position: relative;
  display: flex;
  justify-content: center;
  flex-direction: column;
  align-items: center;
  background: #434242;
  min-height: 100%;

  .loading-title {
    position: fixed;
    color: #fff;
    left: 50%;
    right: 0;
  }

  .tools {
    display: flex;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    width: 100%;
    height: 50px;
    line-height: 50px;
    justify-content: center;
    z-index: 99;
    background: #434242;
    border-bottom: 2px solid #fff;
    color: #fff;
    font-size: 18px;

    .left {
      margin-right: 38%;
      position: absolute;
      display: flex;
      align-items: center;

      i {
        display: flex;
        font-size: 24px;
        padding-top: 13px;
      }

      span {
        margin-right: 50px;
        cursor: pointer;
        display: flex;
        justify-content: space-between;
      }
    }

    .right {
      position: absolute;
      margin-left: 38%;
      span {
        margin-right: 50px;
        cursor: pointer;
      }
    }
  }

  .pdf-viewer {
    width: 50%;
    height: 80%;
    // padding-top: 50px;
    .pdf {
      // width
      height: 100%;
    }
  }

  .video-viewer {
    padding-top: 50px;
    height: 100%;
    width: 100%;
    display: flex;
    justify-content: center;
    align-items: center;

    .video-player {
      width: 80%;
      height: 80%;
    }
  }

  .img-viewer {
    position: relative;
    height: 100%;
    width: 100%;
    display: flex;
    justify-content: center;

    img {
      height: 50%;
      width: 60%;
      object-fit: cover;
    }

    .mask {
      position: absolute;
      left: 0;
      right: 0;
      top: 0;
      bottom: 0;
    }
  }

  .vjs-big-play-button {
    bottom: 10px !important;
    top: unset;
    right: 20px;
    left: unset;
  }
}
</style>

  

四、理清思路后其实这个问题主要还是这个pdf组件的问题、如果更换其他组件很多项目逻辑要更改、考虑到这一点、我们可以去通过切换到下一个数组数据的时候去本地存储下一件的id、再去刷新整个页面的DOM、实现每次请求都只会请求一个url、数据加载就会快很多

<template>
  <div id="pdf-viewer-wrapper">
    <div class="tools">
      <div class="left" v-if="singleArchivesFormId">
        <span @click="prePage(type)"
          ><i class="el-icon-arrow-left"></i>上一件</span
        ><span @click="nextPage(type)"
          >下一件<i class="el-icon-arrow-right"></i
        ></span>
      </div>
      <div class="mid">{{ fileName }}</div>
      <div class="right">
        <span @click="enlarge(type)" class="el-icon-plus"></span>
        <span>{{ parseInt(type === 1 ? imageScal : pdfScal) + "%" }}</span>
        <span @click="narrow(type)" class="el-icon-minus"></span>
      </div>
    </div>
    <div v-if="type === 1" id="img-viewer">
      <img id="img-viewer2" :src="url" alt @error="myFunction" />
      <div class="mask" />
    </div>
    <div v-if="type === 2" id="pdf-viewer">
      <myPdf id="pdf-viewer2" :url="url" :page="pageNum" />
    </div>
    <div v-if="type === 3 && showVideo" class="video-viewer">
      <video-player
        ref="videoPlayer"
        class="video-player vjs-custom-skin"
        :playsinline="true"
        :options="playerOptions"
        @error="myFunction"
      />
    </div>
    <div v-if="type === 4" class="video-viewer">
      <audio :src="url" controls @error="myFunction">
        <source />
        您的浏览器不支持 audio 元素。
      </audio>
    </div>
  </div>
</template>
<script>
// import pdf from "vue-pdf";
import myPdf from "@/views/fileViewer/pdf";
import { videoPlayer } from "vue-video-player";
import "video.js/dist/video-js.css";
import {
  getSingleVolumeAttachmentDetail,
  getSingleVolumeAttachment,
} from "@/api/archivesManagement/singleVolumeMaterial";
import { len } from "zrender/lib/core/vector";
export default {
  name: "Home",
  components: {
    myPdf,
    videoPlayer,
  },
  data() {
    return {
      url: "",
      pageNum: 1,
      pageTotalNum: 1,
      pageRotate: 0,
      // 加载进度
      loadedRatio: 0,
      curPageNum: 0,
      numPages: null, // pdf 总页数
      id: null,
      fileName: null,
      fileType: "image%2Fjpeg",
      showVideo: false,
      singleArchivesFormId: null,
      current: null,
      scal: "50",
      currentStatus: false,
      imageScal: 50,
      pdfScal: 50,
      loading: false,
      pdfId: null,
    };
  },
  computed: {
    type() {
      if (
        this.fileType === "image%2Fpng" ||
        this.fileType === "image%2Fjpeg" ||
        this.fileType === "image/png" ||
        this.fileType === "image/jpeg"
      ) {
        return 1;
      } else if (
        this.fileType === "application%2Fpdf" ||
        this.fileType === "application/pdf"
      ) {
        return 2;
      } else if (
        this.fileType === "video%2Fmp4" ||
        this.fileType === "video/mp4"
      ) {
        return 3;
      } else if (
        this.fileType === "audio%2Fmpeg" ||
        this.fileType === "audio/mpeg"
      ) {
        return 4;
      }
      return 5;
    },
    playerOptions() {
      console.log(this.url);
      return {
        playbackRates: [0.7, 1.0, 1.5, 2.0], // 播放速度
        autoplay: false, // 如果true,浏览器准备好时开始回放。
        muted: false, // 默认情况下将会消除任何音频。
        loop: false, // 导致视频一结束就重新开始。
        preload: "auto", // 建议浏览器在<video>加载元素后是否应该开始下载视频数据。auto浏览器选择最佳行为,立即开始加载视频(如果浏览器支持)
        language: "zh-CN",
        aspectRatio: "16:9", // 将播放器置于流畅模式,并在计算播放器的动态大小时使用该值。值应该代表一个比例 - 用冒号分隔的两个数字(例如"16:9"或"4:3")
        fluid: true, // 当true时,Video.js player将拥有流体大小。换句话说,它将按比例缩放以适应其容器。
        sources: [
          {
            src: this.url, // 路径
            type: "video/mp4", // 类型
          },
        ],
        // poster: "../../static/images/test.jpg", //你的封面地址
        // width: document.documentElement.clientWidth,
        notSupportedMessage: "此视频暂无法播放,请稍后再试", // 允许覆盖Video.js无法播放媒体源时显示的默认信息。
        controlBar: {
          timeDivider: true,
          durationDisplay: true,
          remainingTimeDisplay: false,
          fullscreenToggle: true, // 全屏按钮
        },
      };
    },
  },
  mounted: function () {
    this.getId();
    // console.log(this);
  },
  methods: {
    myFunction(_err) {
      // console.log(err);
      if (this.url.indexOf("www.gdart.site") > -1) {
        this.$message.warning("旧【粤艺研管理系统】丢失该文件,无法读取");
      }
    },
    getSingleVolumeAttachment(current) {
      this.loading = true;
      getSingleVolumeAttachment({
        singleVolumeId: this.singleArchivesFormId,
        current: current,
        size: 50,
      }).then((res) => {
        this.loading = false;
        this.singleArchivesFileList = res.data.records;
      });
    },
    getId() {
      document.oncontextmenu = function () {
        return false;
      };
      if (this.$route.query && this.$route.query.id) {
        this.id = Number(this.$route.query.id);
      }
      if (this.$route.query && this.$route.query.singleArchivesFormId) {
        this.singleArchivesFormId = this.$route.query?.singleArchivesFormId;
        this.current = this.$route.query?.current;
        this.getSingleVolumeAttachment(this.current);
      }
      this.pdfId = Number(localStorage.getItem("fileid"));
      if (this.pdfId) {
        this.getSingleVolumeAttachmentDetail(this.pdfId);
      } else {
        this.getSingleVolumeAttachmentDetail(this.id);
      }
    },
    // 上一件函数,
    prePage(type) {
      this.singleArchivesFileList.forEach((item, index) => {
        if (item.id === this.id) {
          const fileId = this.singleArchivesFileList[index - 1]?.id;
          if (fileId) {
            console.log("fileid", fileId);
            if (type === 2) {
              location.reload();
              localStorage.setItem("fileid", fileId);
            } else {
              localStorage.removeItem("fileid");
              this.getSingleVolumeAttachmentDetail(fileId);
            }
          } else {
            return this.$message.warning("已到最前一件");
          }
        }
      });
    },
    // 下一件函数
    nextPage(type) {
      this.singleArchivesFileList.forEach((item, index) => {
        if (item.id === this.id || item.id === this.pdfId) {
          const fileId = this.singleArchivesFileList[index + 1]?.id;
          if (fileId) {
            console.log("fileid", fileId);
            if (type === 2) {
              location.reload();
              localStorage.setItem("fileid", fileId);
            } else {
              localStorage.removeItem("fileid");
              this.getSingleVolumeAttachmentDetail(fileId);
            }
          } else {
            return this.$message.warning("已到最后一件");
          }
        }
      });
    },
    // 页面顺时针翻转90度。
    clock() {
      this.id;
      this.pageRotate += 90;
    },
    // 页面逆时针翻转90度。
    counterClock() {
      this.pageRotate -= 90;
    },
    // 页面加载回调函数,其中e为当前页数
    pageLoaded(e) {
      this.curPageNum = e;
    },
    // 其他的一些回调函数。
    pdfError(error) {
      console.error(error);
    },
    // 放大
    enlarge(type) {
      this.$nextTick(() => {
        // imageWrapper 获取元素
        const imageWrapper = document.getElementById(
          type === 1 ? "img-viewer" : "pdf-viewer"
        );
        if (type === 1) {
          this.imageScal = (parseFloat(this.imageScal) + 10).toFixed(3);
          imageWrapper.style.width = this.imageScal + "%";
        } else {
          this.pdfScal = (parseFloat(this.pdfScal) + 10).toFixed(3);
          imageWrapper.style.width = this.pdfScal + "%";
        }
      });
    },
    // 缩小
    narrow(type) {
      this.$nextTick(() => {
        // imageWrapper 获取元素
        const imageWrapper = document.getElementById(
          type === 1 ? "img-viewer" : "pdf-viewer"
        );
        if (type === 1) {
          this.imageScal = (parseFloat(this.imageScal) - 10).toFixed(3);
          imageWrapper.style.width = this.imageScal + "%";
        } else {
          this.pdfScal = (parseFloat(this.pdfScal) - 10).toFixed(3);
          imageWrapper.style.width = this.pdfScal + "%";
        }
      });
    },

    getSingleVolumeAttachmentDetail(id) {
      this.loading = true;
      getSingleVolumeAttachmentDetail({ id: id }).then((res) => {
        this.loading = false;
        this.url =
          res.data.filePath.indexOf("https://www.gdart.site/resources/") > -1
            ? res.data.filePath
            : "https://art-archive.oss-cn-shenzhen.aliyuncs.com/" +
              res.data.filePath;
        console.log(this.url);
        this.id = id;
        this.fileName = res.data.fileName;
        this.fileType = res.data.fileType;
        this.showVideo = true;
      });
    },
  },
};
</script>
<style lang="scss">
#pdf-viewer-wrapper {
  position: relative;
  display: flex;
  justify-content: center;
  flex-direction: column;
  align-items: center;
  background: #434242;
  min-height: 100%;

  .tools {
    display: flex;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    width: 100%;
    height: 50px;
    line-height: 50px;
    justify-content: center;
    z-index: 99;
    background: #434242;
    border-bottom: 2px solid #fff;
    color: #fff;
    font-size: 18px;

    .left {
      margin-right: 38%;
      position: absolute;
      display: flex;
      align-items: center;

      i {
        display: flex;
        font-size: 24px;
        padding-top: 13px;
      }

      span {
        margin-right: 50px;
        cursor: pointer;
        display: flex;
        justify-content: space-between;
      }
    }

    .right {
      position: absolute;
      margin-left: 38%;
      span {
        margin-right: 50px;
        cursor: pointer;
      }
    }
  }

  #pdf-viewer {
    width: 50%;
    height: 80%;
    // padding-top: 50px;
    .pdf {
      // width
      height: 100%;
    }
  }

  .video-viewer {
    padding-top: 50px;
    height: 100%;
    width: 100%;
    display: flex;
    justify-content: center;
    align-items: center;

    .video-player {
      width: 80%;
      height: 80%;
    }
  }

  #img-viewer {
    position: relative;
    height: 100%;
    width: 100%;
    display: flex;
    justify-content: center;

    img {
      height: 50%;
      width: 50%;
      object-fit: cover;
    }

    .mask {
      position: absolute;
      left: 0;
      right: 0;
      top: 0;
      bottom: 0;
    }
  }

  .vjs-big-play-button {
    bottom: 10px !important;
    top: unset;
    right: 20px;
    left: unset;
  }
}
</style>

总结、这样就可以规避组件不能二次渲染的问题、无论pdf文件有多大、浏览器只加载一个url时间不会太长、代码没有标注、可以私信我沟通

本文含有隐藏内容,请 开通VIP 后查看