特性更新:
2025.05.27----------------------------------------
- 支持pdf预览默认左侧展开侧边栏目录
- 支持默认【适合页面】全部显示
- 默认【双页模式】
sgFileViewDialog.vue
<template>
<!-- 文件预览弹窗 -->
<div :class="$options.name" v-if="visible">
<!-- 如果不加v-if="visible"弹窗中使用el-tabs组件就会死循环卡死,这个是elementUI的bug -->
<el-dialog
:append-to-body="true"
:close-on-click-modal="true"
:close-on-press-escape="true"
:custom-class="`${$options.name}-el-dialog ${
suffixCN === `文档` ? `noRadius` : ``
}`"
:destroy-on-close="true"
:fullscreen="fullscreen"
:show-close="true"
:title="`预览${form.NAME || form.filename || suffixCN}`"
:top="dialogTop"
:width="`${dialogWidth}px`"
:visible.sync="visible"
v-if="suffixCN !== `图片`"
@keyup.ctrl.enter.native="save"
style="animation: none"
v-loading="loading"
:element-loading-text="elementLoadingText"
>
<div class="video-container" v-if="suffixCN === `视频`">
<!-- 视频 -->
<video
:autoplay="typeof form.autoplay === 'undefined' ? true : form.autoplay"
class="video"
controls
:loop="form.loop"
:muted="form.muted"
playsinline="true"
preload
ref="video"
:src="form.src"
webkit-playsinline="true"
controlslist="nodownload"
/>
</div>
<div class="audio-container" v-else-if="suffixCN === `音频`">
<!-- 音频 -->
<audio
:autoplay="typeof form.autoplay === 'undefined' ? true : form.autoplay"
class="audio"
controls
:loop="form.loop"
:muted="form.muted"
preload
ref="audio"
:src="form.src"
webkit-playsinline="true"
controlslist="nodownload"
/>
</div>
<div class="document-container" v-else-if="suffixCN === `文档`">
<iframe
ref="iframe"
@load="load_iframe"
:src="form.src"
frameborder="no"
scrolling="no"
style="position: absolute; left: 0; top: 0; width: 100%; height: 100%"
/>
</div>
</el-dialog>
<!-- 图片 -->
<el-image
v-if="suffixCN === `图片`"
ref="image"
style="display: none"
src=""
:initial-index="form.initialIndex || 0"
:preview-src-list="form.previewSrcList || [form.src]"
/>
</div>
</template>
<script>
export default {
name: "sgFileViewDialog",
components: {},
data() {
return {
spreadMode: 1, //默认双页模式
currentTime: 0,
fullscreen: false,
dialogWidth: 1000,
dialogTop: ``,
suffix: ``,
suffixCN: ``,
// 视频、音频、图片、文档格式后缀名----------------------------------------
videoSuffixs: [
"mp4",
"wmv",
"mpeg",
"mpg",
"avi",
"mov",
"rm",
"flv",
"swf",
"mkv",
],
audioSuffixs: ["mp3", "m4a", "ogg", "wav", "flac", "aac"],
imageSuffixs: ["jpg", "jpeg", "gif", "bmp", "png", "svg"],
documentSuffixs: [
// office文档
"doc",
"docx",
"xls",
"xlsx",
"ppt",
"pptx",
"pdf", //Adobe Reader 文档
"txt", //记事本
// 其他文档
"ofd",
"xml",
"rtf",
"csv",
],
// ----------------------------------------
loading: false, //加载状态
elementLoadingText: ``, //加载提示文字
visible: false,
form: {}, //表单信息
disabled: false, //是否只读
labelWidth: `120px`,
};
},
props: ["value", "data"],
computed: {},
watch: {
loading(newValue, oldValue) {
newValue || (this.elementLoadingText = ``);
},
value: {
handler(d) {
this.visible = d;
// 每次显示的时候,重置一些参数值
if (d) {
}
},
deep: true,
immediate: true,
},
visible(d) {
this.$nextTick(() => {
this.$refs.image && (this.$refs.image.showViewer = d); //隐藏大图
});
this.$emit("input", d);
},
data: {
handler(newValue, oldValue) {
// console.log(`深度监听${this.$options.name}:`, newValue, oldValue);
if (Object.keys(newValue || {}).length) {
this.form = JSON.parse(JSON.stringify(newValue));
this.$g.convertForm2ComponentParam(`spreadMode`, this);
this.disabled = this.form.disabled;
this.suffix = (this.form.src || ``).split(".").slice(-1)[0];
this.suffix.length > 10 &&
(this.suffix = (this.form.NAME || ``).split(".").slice(-1)[0]); //后缀名超过10的长度就不正常,需要重新通过名称获取后缀名
this.form.suffix && (this.suffix = this.form.suffix);
// 判断文件格式后缀中文
if (this.videoSuffixs.includes(this.suffix)) {
this.suffixCN = `视频`;
this.dialogWidth = 1000;
this.dialogTop = `calc((100vh - 560px) / 2 - 70px)`;
this.playRecordCurrentTime();
this.addEvents();
}
if (this.audioSuffixs.includes(this.suffix)) {
this.suffixCN = `音频`;
this.dialogWidth = 400;
this.dialogTop = `calc(100vh / 2 - 70px)`;
this.playRecordCurrentTime();
this.addEvents();
}
if (
this.imageSuffixs.includes(this.suffix) ||
this.$g.image.isBase64Image(this.form.src)
) {
this.suffixCN = `图片`;
this.$nextTick(
() => this.$refs.image && (this.$refs.image.showViewer = true)
); //显示大图
}
if (this.documentSuffixs.includes(this.suffix)) {
this.suffixCN = `文档`;
this.fullscreen = true;
let { src, filename, keyword, keywords } = this.form;
this.form.src = this.$g.getPDFsrc({ file: src, filename, keyword, keywords });
}
} else {
this.disabled = false; //添加的时候,编辑态
this.form = {
// 默认字段名: 缺省值,
};
}
},
deep: true, //深度监听
immediate: true, //立即执行
},
currentTime(d) {
localStorage[`${this.$options.name}/${this.form.src}/currentTime`] = d;
},
},
created() {},
mounted() {},
beforeDestroy() {
this.removeEvents();
},
methods: {
// 播放上次记录的位置----------------------------------------
playRecordCurrentTime(d) {
this.$nextTick(() => {
let currentTime =
localStorage[`${this.$options.name}/${this.form.src}/currentTime`];
if (currentTime) {
this.$refs.video && (this.$refs.video.currentTime = currentTime); //播放上次的位置
this.$refs.audio && (this.$refs.audio.currentTime = currentTime); //播放上次的位置
}
});
},
// 记录视频、音频播放到哪里了----------------------------------------
addEvents(d) {
this.$nextTick(() => {
this.removeEvents();
this.$refs.video &&
this.$refs.video.addEventListener("timeupdate", this.timeupdate);
this.$refs.audio &&
this.$refs.audio.addEventListener("timeupdate", this.timeupdate);
this.timeupdate();
});
},
removeEvents(d) {
this.$refs.video &&
this.$refs.video.removeEventListener("timeupdate", this.timeupdate);
this.$refs.audio &&
this.$refs.audio.removeEventListener("timeupdate", this.timeupdate);
},
timeupdate(d) {
this.$refs.video && (this.currentTime = this.$refs.video.currentTime);
this.$refs.audio && (this.currentTime = this.$refs.audio.currentTime);
},
// PDF预览■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
load_iframe(d) {
// iframe加载完成后等待一秒再对PDF进行操作,否则可能没有加载完PDF相关组件无法操作----------------------------------------
setTimeout(() => {
this.$nextTick(() => {
this.PDFViewerApplication = this.getPDFViewerApplication();
this.pdfSidebar({ command: `open` }); //打开左侧侧边栏
this.pdfSpreadMode({ spreadMode: this.spreadMode }); //回显单双页模式
});
}, 1000);
},
// 获取PDF控制器
getPDFViewerApplication() {
let PDFViewerApplication;
if (this.$refs.iframe && this.$refs.iframe.contentWindow) {
PDFViewerApplication = this.$refs.iframe.contentWindow.PDFViewerApplication;
}
return PDFViewerApplication;
},
// 跳转到封面
// 跳转到目录
jumpPage({
PDFViewerApplication = this.getPDFViewerApplication(),
currentPageNumber = 1,
} = {}) {
PDFViewerApplication.pdfViewer.currentPageNumber = currentPageNumber;
},
// 单双页模式
pdfSpreadMode({
PDFViewerApplication = this.getPDFViewerApplication(),
spreadMode = 1,
} = {}) {
/* spreadMode:
单页模式: 0,
双页模式: 1,
书籍模式: 2 */
PDFViewerApplication && (PDFViewerApplication.pdfViewer.spreadMode = spreadMode);
},
// 打开侧边栏
pdfSidebar({
PDFViewerApplication = this.getPDFViewerApplication(),
command = `open`,
} = {}) {
PDFViewerApplication && PDFViewerApplication.pdfSidebar[command]();
},
// 适合页面
pdf_page_fit(d) {
let scaleSelect = this.$refs.iframe.contentDocument.querySelector(`#scaleSelect`);
scaleSelect && (scaleSelect.value = `page-fit`);
},
// ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
cancel() {
this.visible = false;
},
},
};
</script>
<style lang="scss" scoped>
.sgFileViewDialog {
}
.el-dialog__wrapper:has(.sgFileViewDialog-el-dialog) {
/*遮罩模糊*/
backdrop-filter: blur(5px);
}
>>> .sgFileViewDialog-el-dialog {
border-radius: 30px;
&.noRadius {
border-radius: 0;
}
box-shadow: 0 10px 50px 0 #00000033;
//关闭按钮
.el-dialog__headerbtn {
.el-dialog__close {
background-color: #409eff;
border-radius: 88px;
box-sizing: border-box;
padding: 5px;
color: white;
}
&:hover {
.el-dialog__close {
background-color: #1f75d5;
color: white;
}
}
}
.video-container {
margin: -20px 0px -10px;
border-radius: 20px;
overflow: hidden;
height: calc(100vh - 180px);
display: flex;
flex-direction: column;
width: 100%;
height: 560px;
overflow: hidden;
background: black;
/*背景图片*/
background-image: url("~@/../static/components/sgVideoPlayer/poster.png");
background-repeat: repeat;
background-position: center;
.video {
transition: 0.382s;
width: 100%;
height: 100%;
object-fit: contain;
object-position: center;
background: transparent;
}
}
.audio-container {
display: flex;
justify-content: center;
align-items: center;
margin: -20px 0px -10px;
border-radius: 20px;
overflow: hidden;
height: calc(100vh - 180px);
display: flex;
flex-direction: column;
width: 100%;
height: 60px;
overflow: hidden;
.audio {
width: 100%;
height: 100%;
}
}
.document-container {
position: relative;
width: 100%;
height: 100%;
}
}
</style>
demo.vue
<template>
<div :class="$options.name">
<el-button @click="readVideo">视频</el-button>
<el-button @click="readAudio">音频</el-button>
<el-button @click="readImage">图片</el-button>
<el-button @click="readDocument">文档</el-button>
<sgFileViewDialog
:data="data_sgFileViewDialog"
v-model="show_sgFileViewDialog"
v-if="show_sgFileViewDialog"
/>
</div>
</template>
<script>
import sgFileViewDialog from "@/vue/components/admin/sgFileViewDialog";
export default {
components: {
sgFileViewDialog,
},
data() {
return {
data_sgFileViewDialog: {},
show_sgFileViewDialog: false,
};
},
props: ["data"],
computed: {},
watch: {},
created() {},
mounted() {},
destroyed() {},
methods: {
rw_sgFileViewDialog({ w = true, d = {} } = {}) {
this.data_sgFileViewDialog = JSON.parse(JSON.stringify(d));
this.data_sgFileViewDialog.disabled = !w;
this.show_sgFileViewDialog = true;
},
readVideo(d) {
this.rw_sgFileViewDialog({
d: {
src: `https://www.*******.cn/share/video/1.mp4`,
},
});
},
readAudio(d) {
this.rw_sgFileViewDialog({
d: {
src: `https://www.*******.cn/share/audio/1.mp3`,
},
});
},
readImage(d) {
this.rw_sgFileViewDialog({
d: {
initialIndex: 1,
src: `https://www.*******.cn/share/image/2.jpg`,
previewSrcList: [
`https://www.*******.cn/share/image/1.jpg`,
`https://www.*******.cn/share/image/2.jpg`,
`https://www.*******.cn/share/image/3.jpg`,
`https://www.*******.cn/share/image/4.jpg`,
`https://www.*******.cn/share/image/5.jpg`,
],
},
});
},
readDocument(d) {
this.rw_sgFileViewDialog({
d: {
src: `http://sr.*******.cn:82/static/help/help.pdf`,
},
});
},
},
};
</script>