Vue2 doc、excel、pdf、ppt、txt、图片以及视频等在线预览

Vue2 doc、excel、pdf、ppt、txt、图片等在线预览

安装

powershell 复制代码
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

powershell 复制代码
npm install @vue/composition-api

使用

目录结构

src\components

直接上代码

src\components\FileView\doc\index.vue

javascript 复制代码
<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

javascript 复制代码
<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文件设置为true
        minColLength: 0,
        minRowLength: 0,
        widthOffset: 10,
        heightOffset: 10,
      },
    };
  },
  methods: {
    renderedHandler() {
      console.log("渲染完成");
    },
    errorHandler() {
      console.log("渲染失败");
    },
  },
};
</script>

src\components\FileView\img\index.vue

javascript 复制代码
<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

javascript 复制代码
<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预览使用微软提供的方法进行文件预览

javascript 复制代码
<template>
  <iframe
    id="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

javascript 复制代码
<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

javascript 复制代码
<template>
  <el-dialog
    title="文件预览"
    :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

javascript 复制代码
<template>
  <div
    class="m-video"
    :class="{ 'u-video-hover': !hidden }"
    :style="`width: ${veoWidth}; height: ${veoHeight};`"
  >
    <video
      ref="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>
    <svg
      v-show="originPlay || showPlay"
      class="u-play"
      :class="{ hidden: hidden }"
      :style="`width: ${playWidth}px; height: ${playWidth}px;`"
      viewBox="0 0 24 24"
    >
      <path
        stroke-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>
      <path
        stroke-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: {
      // 视频播放器宽度,单位 px
      type: [String, Number],
      default: 800,
    },
    height: {
      // 视频播放器高度,单位 px
      type: [String, Number],
      default: 450,
    },
    /*
      参考 MDN 自动播放指南:https://developer.mozilla.org/zh-CN/docs/Web/Media/Autoplay_guide
      Autoplay 功能
      据新政策,媒体内容将在满足以下至少一个的条件下自动播放:
      1.音频被静音或其音量设置为 0
      2.用户和网页已有交互行为(包括点击、触摸、按下某个键等等)
      3.网站已被列入白名单;如果浏览器确定用户经常与媒体互动,这可能会自动发生,也可能通过首选项或其他用户界面功能手动发生
      4.自动播放策略应用到<iframe>或者其文档上
      autoplay:由于目前在最新版的Chrome浏览器(以及所有以Chromium为内核的浏览器)中,
      已不再允许自动播放音频和视频。就算你为video或audio标签设置了autoplay属性也一样不能自动播放!
      解决方法:设置视频 autoplay 时,视频必须设置为静音 muted: true 即可实现自动播放,
      然后用户可以使用控制栏开启声音,类似某宝商品自动播放的宣传视频逻辑
    */
    autoplay: {
      // 视频就绪后是否马上播放,优先级高于 preload
      type: 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中增加全局组件引用

javascript 复制代码
import FileView from '@/components/FileView'
Vue.component('FileView',FileView)

如果不使用全局挂载,那么请局部注册

我的使用场景

javascript 复制代码
<FileView :open.sync="fileViewOpen" :url="fileUrl" v-if="fileViewOpen" />
相关推荐
今日之风甚是温和1 小时前
【Excel】拆分多个sheet,为单一表格
java·excel·sheet·vb宏
如意机反光镜裸1 小时前
Excel如何批量导入图片
excel
拾荒的小海螺13 小时前
JAVA:探索 PDF 文字提取的技术指南
java·开发语言·pdf
村东头老张13 小时前
Java 实现PDF添加水印
java·开发语言·pdf
一棵开花的树,枝芽无限靠近你15 小时前
【PPTist】开源PPT编辑器初体验
编辑器·powerpoint
滨HI016 小时前
python中Pandas操作excel补全内容
python·excel·pandas
Leuanghing16 小时前
使用Python生成卡方分布表并导出为Excel文件
python·excel·pandas·scipy·卡方分布表
叮当喵是mao18 小时前
python基础知识(七)——写入excel
android·python·excel
好美啊啊啊啊!20 小时前
Thymeleaf模板引擎生成的html字符串转换成pdf
pdf·html
zhentiya1 天前
曼昆《经济学原理》第八版课后答案及英文版PDF
大数据·pdf