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" />
相关推荐
Swift社区5 分钟前
Excel 列名称转换问题 Swift 解答
开发语言·excel·swift
neeef_se1 小时前
Vue中使用a标签下载静态资源文件(比如excel、pdf等),纯前端操作
前端·vue.js·excel
℘团子এ1 小时前
js和html中,将Excel文件渲染在页面上
javascript·html·excel
小奥超人5 小时前
PDF无法打印!怎么办?
windows·经验分享·pdf·办公技巧·pdf加密解密
菠萝蚊鸭10 小时前
Dhatim FastExcel 读写 Excel 文件
java·excel·fastexcel
一只小灿灿10 小时前
VB.NET在 Excel 二次开发中的全面应用
.net·excel
是小崔啊13 小时前
开源轮子 - EasyExcel01(核心api)
java·开发语言·开源·excel·阿里巴巴
Excel_easy14 小时前
批量识别工作表中二维码信息-Excel易用宝
excel·wps
m0_7482412321 小时前
ElasticPDF-新国产 PDF 编辑器开发框架(基于 pdf.js Web PDF批注开发,实现高亮多边形橡皮擦历史记录保存注释文字)
前端·pdf·编辑器
ComPDFKit1 天前
开源 JS PDF 库比较
pdf