Vue2 doc、excel、pdf、ppt、txt、图片等在线预览
- 安装
- 使用
- 目录结构
- 直接上代码
- src\components\FileView\doc\index.vue
- src\components\FileView\excel\index.vue
- src\components\FileView\img\index.vue
- src\components\FileView\pdf\index.vue
- src\components\FileView\ppt\index.vue
- src\components\FileView\txt\index.vue
- src\components\FileView\index.vue
- src\components\FileView\video\index.vue
- 应用实例
- 我的使用场景
安装
npm install --save @vue-office/docx @vue-office/excel @vue-office/pdf vue-demi@0.14.6
vue-demi@0.14.6; 其中 @0.14.6 为版本号,可以不加,默认下载最新版。
如果是 vue2.6 版本或以下还需要额外安装 @vue/composition-api
npm install @vue/composition-api
使用
目录结构
src\components
直接上代码
src\components\FileView\doc\index.vue
<template><div><vue-office-docx:src="docx"style="height: 75vh"@rendered="rendered"@error="errorHandler"/></div>
</template><script>
//引入VueOfficeDocx组件
import VueOfficeDocx from "@vue-office/docx";
//引入相关样式
import "@vue-office/docx/lib/index.css";export default {components: {VueOfficeDocx,},props: {docx: {type: String,default:"http://qncdn.qkongtao.cn/lib/teamadmin/files/Hadoop2.7.1%E4%BC%AA%E5%88%86%E5%B8%83%E5%BC%8F%E9%9B%86%E7%BE%A4%E5%AE%89%E8%A3%85%E6%96%87%E6%A1%A3.docx", //设置文档网络地址,可以是相对地址},},data() {return {};},methods: {rendered() {console.log("渲染完成");},errorHandler() {console.log("渲染失败");},},
};
</script>
src\components\FileView\excel\index.vue
<template><vue-office-excel:src="excel":options="options"@rendered="renderedHandler"@error="errorHandler"style="height: 75vh"/>
</template><script>
//引入VueOfficeExcel组件
import VueOfficeExcel from "@vue-office/excel";
//引入相关样式
import "@vue-office/excel/lib/index.css";export default {components: {VueOfficeExcel,},props: {excel: {type: String,default:"http://qncdn.qkongtao.cn/lib/teamadmin/files/2021%E5%B1%8A%E5%85%A8%E5%9B%BD%E5%90%84%E5%9C%B0%E6%B4%BE%E9%81%A3%E5%9C%B0%E5%9D%80.xlsx", //设置文档地址},},data() {return {options: {xls: true, //预览xlsx文件设置为false 预览xls文件设置为trueminColLength: 0,minRowLength: 0,widthOffset: 10,heightOffset: 10,},};},methods: {renderedHandler() {console.log("渲染完成");},errorHandler() {console.log("渲染失败");},},
};
</script>
src\components\FileView\img\index.vue
<template><div style="display: flex; justify-content: center"><el-image :src="imgUrl" :preview-src-list="[imgUrl]"> fit="contain"></el-image></div>
</template><script>
export default {props: {imgUrl: {type: String,default: "",},},components: {},data() {return {};},methods: {closeImage() {},},
};
</script>
src\components\FileView\pdf\index.vue
<template><vue-office-pdf :src="pdf" style="height: 75vh" @rendered="rendered" />
</template><script>
//引入VueOfficePdf组件
import VueOfficePdf from "@vue-office/pdf";export default {components: {VueOfficePdf,},props: {pdf: {type: String,default:"http://qncdn.qkongtao.cn/lib/teamadmin/files/%E6%B7%B1%E5%9C%B3-xx-Java%E9%AB%98%E7%BA%A7.pdf",},},data() {return {};},methods: {rendered() {console.log("渲染完成");},},
};
</script>
src\components\FileView\ppt\index.vue
PPT预览使用微软提供的方法进行文件预览
<template><iframeid="iframe1"width="100%"height="700px"frameborder="0"border="0"marginwidth="0"marginheight="0"scrolling="no"allowtransparency="no":src="'https://view.officeapps.live.com/op/embed.aspx?src=' + fileUrl"></iframe>
</template><script>
export default {props: {fileUrl: {type: String,default: "",},},components: {},data() {return {};},methods: {},
};
</script>
src\components\FileView\txt\index.vue
<template><div><pre class="pre-txt">{{ txtContent }}</pre></div>
</template><script>
import axios from "axios";
export default {components: {},props: {fileUrl: {type: String,default: "https://example.com/your-txt-file.txt",},},data() {return {txtContent: "",};},mounted() {this.fetchTxtFile();},methods: {fetchTxtFile() {axios.get(this.fileUrl).then((response) => {this.txtContent = response.data;}).catch((error) => {console.error("获取txt文件失败:", error);});},},
};
</script>
<style scoped>
.pre-txt {font-size: 12px;padding: 0;width: 100%;max-height: 70vh;min-height: 70vh;margin: 0;background: #f0f0f0;line-height: 20px; /* 行距 */overflow: auto; /* 超出宽度出现滑动条 */overflow-y: auto; /* 作用是隐藏IE的右侧滑动条 */
}
</style>
src\components\FileView\index.vue
<template><el-dialogtitle="文件预览":visible.sync="open"width="50vw":before-close="handleClose":close-on-click-modal="true"><DOC :docx="url" v-if="componentToUse === 'DOC'"></DOC><PDF :pdf="url" v-if="componentToUse === 'PDF'"></PDF><EXCEL :excel="url" v-if="componentToUse === 'EXCEL'"></EXCEL><TXT :fileUrl="url" v-if="componentToUse === 'TXT'"></TXT><IMG :imgUrl="url" v-if="componentToUse === 'IMG'"></IMG><PPT :fileUrl="url" v-if="componentToUse === 'PPT'"></PPT><!-- <span slot="footer" class="dialog-footer"><el-button @click="handleClose" size="small">关 闭</el-button></span> --><div v-if="componentToUse === 'WZ'">不支持的文件类型</div></el-dialog>
</template><script>
import DOC from "./doc/index.vue";
import PDF from "./pdf/index.vue";
import EXCEL from "./excel/index.vue";
import TXT from "./txt/index.vue";
import IMG from "./img/index.vue";
import PPT from "./ppt/index.vue";export default {components: {DOC,PDF,EXCEL,TXT,IMG,PPT,},props: {open: {type: Boolean,default: false,},url: {type: String,default:"http://qncdn.qkongtao.cn/lib/teamadmin/files/Hadoop2.7.1%E4%BC%AA%E5%88%86%E5%B8%83%E5%BC%8F%E9%9B%86%E7%BE%A4%E5%AE%89%E8%A3%85%E6%96%87%E6%A1%A3.docx", //设置文档网络地址,可以是相对地址},},data() {return {componentToUse: null, // 用于存储要使用的组件};},watch: {url() {// 当 url 改变时,重新判断文件类型并设置组件this.determineComponentType();},},created() {// 在组件创建时判断文件类型并设置组件this.determineComponentType();},methods: {rendered() {console.log("渲染完成");},handleClose() {this.$emit("update:open", false);},determineComponentType() {const fileExtension = this.url.split(".").pop().toLowerCase();switch (fileExtension) {case "docx":this.componentToUse = "DOC";break;case "pdf":this.componentToUse = "PDF";break;case "xlsx":case "xls":this.componentToUse = "EXCEL";break;case "txt":case "html":case "vue":case "js":case "json":this.componentToUse = "TXT";break;case "png":case "jpg":case "jpeg":this.componentToUse = "IMG";break;case "ppt":case "pptx":this.componentToUse = "PPT";break;default:console.error("不支持的文件类型");this.componentToUse = "WZ";}},},
};
</script>
src\components\FileView\video\index.vue
<template><divclass="m-video":class="{ 'u-video-hover': !hidden }":style="`width: ${veoWidth}; height: ${veoHeight};`"><videoref="veoRef"class="u-video":style="`object-fit: ${zoom};`":src="src":poster="veoPoster":autoplay="autoplay":controls="!originPlay && controls":loop="loop":muted="autoplay || muted":preload="preload"crossorigin="anonymous"@loadeddata="poster ? () => false : getPoster()"@pause="showPlay ? onPause() : () => false"@playing="showPlay ? onPlaying() : () => false"@click.prevent.once="onPlay"v-bind="$attrs">您的浏览器不支持video标签。</video><svgv-show="originPlay || showPlay"class="u-play":class="{ hidden: hidden }":style="`width: ${playWidth}px; height: ${playWidth}px;`"viewBox="0 0 24 24"><pathstroke-linecap="round"stroke-linejoin="round"stroke-width="1.5"d="M4.75 6.75C4.75 5.64543 5.64543 4.75 6.75 4.75H17.25C18.3546 4.75 19.25 5.64543 19.25 6.75V17.25C19.25 18.3546 18.3546 19.25 17.25 19.25H6.75C5.64543 19.25 4.75 18.3546 4.75 17.25V6.75Z"></path><pathstroke-linecap="round"stroke-linejoin="round"stroke-width="1.5"d="M15.25 12L9.75 8.75V15.25L15.25 12Z"></path></svg></div>
</template>
<script>
export default {name: "Video",props: {src: {// 视频文件url,必传,支持网络地址 https 和相对地址 require('@/assets/files/Bao.mp4')type: String,required: true,default: "",},poster: {// 视频封面url,支持网络地址 https 和相对地址 require('@/assets/images/Bao.jpg')type: String,default: "",},second: {// 在未设置封面时,自动截取视频第 second 秒对应帧作为视频封面type: Number,default: 0.5,},width: {// 视频播放器宽度,单位 pxtype: [String, Number],default: 800,},height: {// 视频播放器高度,单位 pxtype: [String, Number],default: 450,},/*参考 MDN 自动播放指南:https://developer.mozilla.org/zh-CN/docs/Web/Media/Autoplay_guideAutoplay 功能据新政策,媒体内容将在满足以下至少一个的条件下自动播放:1.音频被静音或其音量设置为 02.用户和网页已有交互行为(包括点击、触摸、按下某个键等等)3.网站已被列入白名单;如果浏览器确定用户经常与媒体互动,这可能会自动发生,也可能通过首选项或其他用户界面功能手动发生4.自动播放策略应用到<iframe>或者其文档上autoplay:由于目前在最新版的Chrome浏览器(以及所有以Chromium为内核的浏览器)中,已不再允许自动播放音频和视频。就算你为video或audio标签设置了autoplay属性也一样不能自动播放!解决方法:设置视频 autoplay 时,视频必须设置为静音 muted: true 即可实现自动播放,然后用户可以使用控制栏开启声音,类似某宝商品自动播放的宣传视频逻辑*/autoplay: {// 视频就绪后是否马上播放,优先级高于 preloadtype: Boolean,default: false,},controls: {// 是否向用户显示控件,比如进度条,全屏等type: Boolean,default: true,},loop: {// 视频播放完成后,是否循环播放type: Boolean,default: false,},muted: {// 是否静音type: Boolean,default: false,},preload: {// 是否在页面加载后载入视频,如果设置了autoplay属性,则preload将被忽略;type: String,default: "metadata", // auto:一旦页面加载,则开始加载视频; metadata:当页面加载后仅加载视频的元数据 none:页面加载后不应加载视频},showPlay: {// 播放暂停时是否显示播放器中间的暂停图标type: Boolean,default: true,},playWidth: {// 中间播放暂停按钮的边长type: Number,default: 96,},zoom: {// video的poster默认图片和视频内容缩放规则type: String,default: "contain", // none:(默认)保存原有内容,不进行缩放; fill:不保持原有比例,内容拉伸填充整个内容容器; contain:保存原有比例,内容以包含方式缩放; cover:保存原有比例,内容以覆盖方式缩放},},data() {return {veoPoster: this.poster,originPlay: true,hidden: false,};},computed: {veoWidth() {return '100%';},veoHeight() {if (typeof this.height === "number") {return this.height + "px";}return this.height;},},mounted() {if (this.autoplay) {this.hidden = true;this.originPlay = false;}/*自定义设置播放速度,经测试:在vue2中需设置:this.$refs.veoRef.playbackRate = 2在vue3中需设置:veo.value.defaultPlaybackRate = 2*/// this.$refs.veoRef.playbackRate = 2},methods: {/*loadedmetadata 事件在元数据(metadata)被加载完成后触发loadeddata 事件在媒体当前播放位置的视频帧(通常是第一帧)加载完成后触发若在移动/平板设备的浏览器设置中开启了流量节省(data-saver)模式,该事件则不会被触发。preload 为 none 时不会触发*/getPoster() {// 在未设置封面时,自动获取视频0.5s对应帧作为视频封面// 由于不少视频第一帧为黑屏,故设置视频开始播放时间为0.5s,即取该时刻帧作为封面图this.$refs.veoRef.currentTime = this.second;// 创建canvas元素const canvas = document.createElement("canvas");const ctx = canvas.getContext("2d");// canvas画图canvas.width = this.$refs.veoRef.videoWidth;canvas.height = this.$refs.veoRef.videoHeight;ctx.drawImage(this.$refs.veoRef, 0, 0, canvas.width, canvas.height);// 把canvas转成base64编码格式this.veoPoster = canvas.toDataURL("image/png");},onPlay() {if (this.originPlay) {this.$refs.veoRef.currentTime = 0;this.originPlay = false;}if (this.autoplay) {this.$refs.veoRef.pause();} else {this.hidden = true;this.$refs.veoRef.play();}},onPause() {this.hidden = false;},onPlaying() {this.hidden = true;},},
};
</script>
<style scoped>
* {box-sizing: border-box;margin: 0;padding: 0;
}
.m-video {display: inline-block;position: relative;background: #000;cursor: pointer;
}.u-play {position: absolute;top: 0;right: 0;bottom: 0;left: 0;margin: auto;fill: none;color: #fff;pointer-events: none;opacity: 0.7;transition: opacity 0.3s;
}
.hidden {opacity: 0;
}
.u-video {display: inline-block;width: 100%;height: 100%;vertical-align: bottom;
}
.u-video-hover {
}
</style>
应用实例
建议在main.js
中增加全局组件引用
import FileView from '@/components/FileView'
Vue.component('FileView',FileView)
如果不使用全局挂载,那么请局部注册
我的使用场景
<FileView :open.sync="fileViewOpen" :url="fileUrl" v-if="fileViewOpen" />