目录
一、封装的pdf.vue 添加了数据加载loading的效果
二、基于vue封装的pdf组件不能去监听获取到的新url二次去渲染,由于我这边的业务、pdf文件超过100M左右、如果全部去获取到数组里面的数据全部加载回来再本地再次渲染、导致会内存溢出
三、重构之后的pdf渲染组件、通过请求全部的数组数据的url加载到本地、再去通过index对比去渲染、这个逻辑如果pdf文件不大、完全是没问题、考虑到pdf文件过大这个逻辑并不适用
总结、这样就可以规避组件不能二次渲染的问题、无论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 后查看