vue2 文件在线预览

822 阅读1分钟

新建 previewFile.vue

<template>
  <div class="">
    <div
      v-if="['doc', 'docx', 'xls', 'xlsx'].includes(fileType)"
      class="button_download"
    >
      <el-button type="text" @click="handleDownload">下载</el-button>
    </div>
    <div style="width: 100%; height: 100%">
      <img
        v-if="imgUrl"
        :src="imgUrl"
        alt=""
        style="width: 100%; height: 100%"
      />
      <!-- pdf和txt使用iframe -->
      <iframe
        v-if="pdfUrl"
        :src="pdfUrl"
        frameborder="0"
        style="width: 100%; height: 100%; min-height: 100vh"
      ></iframe>
      <video
        v-if="videoUrl"
        :src="videoUrl"
        controls
        style="width: 100%; height: 100%; max-height: 800px"
      ></video>
      <div v-show="docFile">
        <div ref="file"></div>
      </div>
      <div v-if="xlsFile" class="excel-view-container">
        <!-- Excel使用tab选项卡来模拟表格里的sheet业 -->
        <el-tabs
          v-if="sheetNames && sheetNames.length"
          type="border-card"
          @tab-click="handleClick"
        >
          <el-tab-pane
            v-for="(item, index) in sheetNames"
            :key="index"
            :label="item"
          >
            <div id="excelView" v-html="excelView"></div>
          </el-tab-pane>
        </el-tabs>
      </div>
    </div>
  </div>
</template>
<script>
import * as docx from "docx-preview";
import XLSX from "xlsx";
export default {
  props: ["previewType", "previewUrl"],
  data() {
    return {
      fileType: "", //文件类型
      data: "", //文件路径,blob 类型

      imgUrl: "", //图片路径
      pdfUrl: "", //pdf路径
      videoUrl: "", //视频路径
      excelView: "", //表格转换后的html数据
      docFile: false, //是否是word文件
      xlsFile: false, //是否是Excel文件
      execlArraybufferData: null, //Excelblob转换为arraybuff数据
      sheetNames: null, //从数据中获取到的sheet页数组
      workbooks: null,
    };
  },
  watch: {
    previewType: {
      handler(value) {
        this.fileType = value;
      },
      immediate: true, // 重点
      deep: true, // 重点
    },

    previewUrl: {
      handler(value) {
        this.data = value;
        this.sheetNames = null
        this.workbooks = null
        this.filePreviewPDF();
      },
      immediate: true, // 重点
      deep: true, // 重点
    },
  },
  methods: {
    handleDownload() {
      this.$emit("handleDownload");
    },
    // 预览文件
    filePreviewPDF() {
      this.pdfUrl = "";
      this.docFile = false;
      this.xlsFile = false;
      if (this.fileType == "pdf" || this.fileType == "txt") {
        // pdf和文本类型的,用iframe打开
        this.pdfUrl = window.URL.createObjectURL(this.data);
      } else if (this.fileType == "doc" || this.fileType == "docx") {
        // word类型的用docx-preview插件
        this.docFile = true;
        this.$nextTick(() => {
          docx
            .renderAsync(this.data, this.$refs.file)
            .then((x) => console.log("docx: finished", x));
        });
      } else if (this.fileType == "xls" || this.fileType == "xlsx") {
        // 表格类型的用xlsx插件
        this.xlsFile = true;
        this.XLSX = XLSX;
        // this.execlType = type;
        let reader = new FileReader();
        reader.readAsArrayBuffer(this.data); // blob类型转换为ArrayBuffer类型
        this.tabChange(0, reader);
      } else {
        this.handleClose();
        this.$message.error("不支持此文件预览");
      }
    },
    handleClick(data) {
      this.tabChange(data.index);
    },
    tabChange(index, reader) {
      this.excelView = "";
      let XLSX = this.XLSX;
      let _this = this;
      if (!this.sheetNames) {
        // 文件转换加载完成后
        reader.onload = function () {
          let arraybufferData = this.result;
          this.execlArraybufferData = arraybufferData;
          let data = new Uint8Array(arraybufferData); // es2017的方法
          let workbook = XLSX.read(data, { type: "array" }); // 得到表格的array数据
          _this.workbooks = workbook; // 赋值到此组件最外面,一会要用
          let sheetNames = workbook.SheetNames; // 得到execl工作表名称集合,结果类似这样['sheet1','sheet2']
          _this.sheetNames = sheetNames; // 赋值到此组件最外面,一会要用
          let worksheet = workbook.Sheets[sheetNames[index]]; // 获取第几个工作表0就是'sheet1',以此类推
          _this["excelView"] = XLSX.utils.sheet_to_html(worksheet); // 把表格的array数据转换成html数据
          _this.$nextTick(function () {
            // DOM加载完毕后执行,解决HTMLConnection有内容但是length为0问题。
            _this.setStyle4ExcelHtml();
          });
        };
      } else {
        let worksheet = this.workbooks.Sheets[this.sheetNames[index]]; // 获取第几个工作表0就是'sheet1',以此类推
        this["excelView"] = XLSX.utils.sheet_to_html(worksheet);
      }
    },
    // 设置Excel转成HTML后的样式
    setStyle4ExcelHtml() {
      const excelViewDOM = document.getElementById("excelView");
      if (excelViewDOM) {
        const excelViewTDNodes = excelViewDOM.getElementsByTagName("td"); // 获取的是HTMLConnection
        if (excelViewTDNodes) {
          const excelViewTDArr = Array.prototype.slice.call(excelViewTDNodes);
          for (const i in excelViewTDArr) {
            const id = excelViewTDArr[i].id; // 默认生成的id格式为sjs-A1、sjs-A2......
            if (id) {
              const idNum = id.replace(/[^0-9]/gi, ""); // 提取id中的数字,即行号
              if (idNum && (idNum === "1" || idNum === 1)) {
                // 第一行标题行
                excelViewTDArr[i].classList.add("class4Title");
              }
              if (idNum && (idNum === "2" || idNum === 2)) {
                // 第二行表头行
                excelViewTDArr[i].classList.add("class4TableTh");
              }
            }
          }
        }
      }
    },
    handleClose() {
      this.$emit("closeDialog", false);
    },
  },
};
</script>
<style lang="scss">
.button_download {
  display: flex;
  width: 100%;
  justify-content: flex-end;
}
#excelView {
  table {
    color: #000;
    width: 100%;
    border-collapse: collapse;
    border: solid 1px;
    tr,
    td,
    th {
      border: solid 1px;
      text-align: center;
      padding: 10px;
    }
  }
}

</style>

组件里面使用

  <el-dialog
      title="预览附件"
      :visible.sync="previewAnnex"
      :fullscreen="true"
      :close-on-click-modal="false"
      :close-on-press-escape="false"
      :destroy-on-close="true"
    >
      <previewFile
        :preview-url="previewUrl"
        :preview-type="previewType"
        @handleDownload="handleDownload"
      />

      <div slot="footer" class="batch-dialog-footer">
        <el-button type="primary" @click="previewAnnex = false">关闭</el-button>
      </div>
    </el-dialog>
    


 data() {
    return {
      // 文件预览
      previewAnnex: false,
      previewUrl: '',
      previewType: '',
      filename: '',
    };
  },
  methods:{
      lookPdf(base){
          getImageOfMinio(base).then((res) => {
              if (res.data.code === 1) return this.$message.error(res.data.msg)
              let wj = encodeURIComponent(res.data.data)
              wj = decodeURIComponent(wj)
              var myBlob = this.dataURLtoBlob(wj)
              this.previewUrl = myBlob
              this.previewType = this.iconByType(res.config.url)
              this.filename = res.config.url
              this.previewAnnex = true
            })
      },
 
   // 获取文件后缀名
    iconByType(filename) {
      return filename.substring(filename.lastIndexOf('.') + 1, filename.length)
    },
    handleDownload() {
      //生成地址
      var myUrl = URL.createObjectURL(this.previewUrl)

      //下载文件
      this.downloadFile(myUrl, this.filename)
    },
    dataURLtoBlob(dataurl) {
      let arr = dataurl.split(',')
      let mime = arr[0].match(/:(.*?);/)[1],
        bstr = atob(arr[1]),
        n = bstr.length,
        u8arr = new Uint8Array(n)
      while (n--) {
        u8arr[n] = bstr.charCodeAt(n)
      }
      return new Blob([u8arr], { type: mime })
    },
    downloadFile(url, name) {
      let a = document.createElement('a')
      a.setAttribute('href', url)
      a.setAttribute('download', name)
      a.setAttribute('target', '_blank')
      let clickEvent = document.createEvent('MouseEvents')
      clickEvent.initEvent('click', true, true)
      a.dispatchEvent(clickEvent)
    },
  }