likes
comments
collection
share

前端文件流文件预览下载(支持excel与pdf)

作者站长头像
站长
· 阅读数 54

前端实现

前提,不要引入mock,不然会有bug!!!!

在开发过程中,产品提出需求,希望文件可以先在线预览需要下载的文件,但又不希望以网址的方式返给前端,以文件流的形式返给前端,这样以保证安全性。

经过在各种网站上流浪几个小时后,确定使用iframe与xlsx的方案来分别预览pdf表格

下面是代码及介绍


    <!-- 预览弹框 -->
    <el-dialog
      title="预览"
      top="8vh"
      width="70%"
      :visible.sync="dialogPreVisible"
      @close="()=>{pdf = ''}"
    >
      <iframe
        style="width: 100%; height: 450px"
        frameborder="0"
        width="100%"
        height="620px"
        :src="pdf"
        v-if="pdf"
        type="application/x-google-chrome-pdf"
        ref="previewFrame"
      ></iframe>
      <div 
        class="table-html-wrap"
        v-if="!pdf"
        style="width: 100%; height: 420px;overflow: auto;"
        id="tableHtml"
      ></div>
    </el-dialog>

首先使用了一个弹框进行预览,v-if切换pdf和excel,接下来就是预览部分js

  // 预览
    async doPreview(row, col) {
    // row col 为发送请求的参数
      const res = await getPdf(row[`${col}Id`]);
      if (
        res.fileType !== "pdf" &&
        res.fileType !== "xlsx" &&
        res.fileType !== "xls"
      ) {
        this.$message.warning("只支持pdf与excel格式的文件预览");
        return;
      }
      let typeList = {
        pdf: "application/pdf",
        xls: "application/vnd.ms-excel",
        xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
      };
      const blob = new Blob([res], { type: typeList[res.fileType] });
      if (res.fileType === "pdf") {
        this.pdf = URL.createObjectURL(blob);
      } else {
        const reader = new FileReader();
        reader.onload = (e) => {
          const data = new Uint8Array(e.target.result);
          let workbook = XLSX.read(data, { type: "array" }); // 解析数据
          this.tableToHtml(workbook);
        };
        reader.readAsArrayBuffer(blob);
      }
      this.dialogPreVisible = true;
    },

res.fileType这个信息并不是后端返回的(文件的后缀及格式),而是在前端请求拦截处统一加上的,如下

service.interceptors.response.use(
  (response) => {
    const res = response.data;
    // console.log(response, '兰拦截')
    if (response.config.responseType == "blob") {
      if (response.headers.get("Content-Disposition")) {
        let type = response.headers.get("Content-Disposition");
        // console.log( type.substring(type.lastIndexOf('.') + 1))
        res.fileType = type.substring(type.lastIndexOf(".") + 1);
      }
      return res;
    }
    // loadingInstance.close()
    if ( res&&res.code !== "000000") {
      // console.log(res,'res')
      Message({
        message: res.mesg || "Error",
        type: "error",
        duration: 5 * 1000,
      });
      // console.log(res, '222')
    } 
    // console.log(res,'res1111');
    return res
  },
  • 使用了response.headers.get("Content-Disposition");读取后端返回的响应头(这步需要后端配合)
  • 枚举文件格式对应的blob格式,在此我也就不为了这些水字数了,具体其他格式可参考mdn网站点击闪现
  • 然后就可以res.fileType拿到文件的格式,然后根据文件格式设置对应的配置

下面是pdf预览代码的解释

 const blob = new Blob([res], { type: typeList[res.fileType] });

Blob() 构造函数可以通过其他对象创建 blob。

this.pdf = URL.createObjectURL(blob);

下面是表格预览代码的解释

npm i xlsx 或者 yarn add xlsx

调用 URL.createObjectURL() 方法,将 blob 转换为一个 url,然后将url传入ifram的src中,pdf的预览就完成了

const reader = new FileReader();

创建一个FileReader对象,FileReader对象允许Wb应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用fi1e或B1ob对象指定要读取的文件或数据。

reader.onload = (e) => {
              const data = new Uint8Array(e.target.result);
              let workbook = XLSX.read(data, { type: "array" }); // 解析数据
              this.tableToHtml(workbook);
};
reader.readAsArrayBuffer(blob);

reader.readAsArrayBuffer(blob)将blob类型转换为arrayBuffer,然后在reader.onload的函数用e.target.result拿到被转换后的结果,然后使用ew Uint8Array()构造函数将流格式的返回值转换,再使用XLSX.read(data, { type: "array" })读取结果,最后调用this.tableToHtml()函数渲染表格

    tableToHtml(workbook) {
      var worksheet = workbook.Sheets[workbook.SheetNames[0]];
      // var innerHTML = XLSX.utils.sheet_to_html(worksheet);
      if (document.querySelector("#tableHtml")) {
        document.querySelector("#tableHtml").innerHTML =
          XLSX.utils.sheet_to_html(worksheet);
        document.querySelector(".table-html-wrap table");
        let trs = document.querySelectorAll("tr");
        trs.forEach((tr) => {
          if (!tr.innerText.trim()) {
            tr.remove();
          }
        });
        document.querySelector(".el-dialog__body").style.overflowX = "auto";
      }
      let tds = document.querySelectorAll("td");
    },


  • 获取dom,tableHtml,并使用 XLSX.utils.sheet_to_html(worksheet)将xlsx读取的结果渲染到页面上

    let trs = document.querySelectorAll("tr");
    trs.forEach((tr) => {
    if (!tr.innerText.trim()) {
    tr.remove();
    }
    });
    document.querySelector(".el-dialog\_\_body").style.overflowX = "auto";
    
    

这段代码是处理,预览出来的结果会出现空格的问题

转载自:https://juejin.cn/post/7241096652919472186
评论
请登录