后端返回文件流 前端进行下载 elementui+vue2.0

在项目中遇到后端将excel文件通过文件流的方式返回给前端 前端需要进行下载 实验很久之后实现的方式如下

首先需要知道后端返回文件流的时候 我们需要在请求的时候将responseType的值设置为blob

由于我的项目中的请求是进行过封装的 没有搞清楚怎么添加这个设置 因此我在需要下载的页面单独引入了axios

import axios from 'axios'    // 依赖中已经下载过axios了 直接引入即可

以下是实现布局的代码

<div class="download">
  <el-date-picker
    v-model="time"
    type="daterange"
    align="right"
    unlink-panels
    range-separator="至"
    start-placeholder="开始日期"
    end-placeholder="结束日期"
    :picker-options="pickerOptions"
    value-format="yyyy-MM-dd"
    size="small"
    @change="getTime"
  >
  </el-date-picker>

  <el-button
    type="success"
    size="small"
    @click="download"
    icon="el-icon-download"
    :disabled="isDownload"
  >
    导出列表
  </el-button>
</div>

 以下是data中定义的代码

data(){
    return {
      isDownload: true, // 下载按钮是否可点击
      time: "", // 下载时间
      // 时间选择器快捷选项
      pickerOptions: {
        shortcuts: [
          {
            text: "最近一周",
            onClick(picker) {
              const end = new Date();
              const start = new Date();
              start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
              picker.$emit("pick", [start, end]);
            },
          },
          {
            text: "最近一个月",
            onClick(picker) {
              const end = new Date();
              const start = new Date();
              start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
              picker.$emit("pick", [start, end]);
            },
          },
          {
            text: "最近三个月",
            onClick(picker) {
              const end = new Date();
              const start = new Date();
              start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
              picker.$emit("pick", [start, end]);
            },
          },
        ],
      },
      isClick: false, // 是否点击下载按钮
    }
}

以下是下载实现功能的代码 

// 控制按钮的禁用状态 在日期选择后才允许按钮点击
getTime(val) {
  if (val) {
    this.isDownload = false;
  } else {
    this.isDownload = true;
  }
},

// 下载
async download() {
      // 防止重复点击
      if (!this.isClick) {
        this.isClick = true;
        // 因为需要筛选日期之后再发送请求给后端 这里定义了请求参数 time是组件v-model绑定的值
        let params = {
          start_time: this.time[0] + " 00:00:00",
          end_time: this.time[1] + " 23:59:59",
        };
        // 不同环境的请求地址不同 我这里是直接从地址栏取的请求地址的前半段,然后拼接后端给的接口地址
        let url = window.location.href.split("#")[0];
        // 当为开发环境时
        if (url.includes("localhost")) {
          url = url + "api/admin/exports";
        } else {
          url = url + "admin/exports";
        }
        // 发送请求
        axios
          .request({
            url, //请求路径
            responseType: "blob",
            method: "get",
            params,
          })
          .then((res) => {
            //此处有个坑。这里用content保存文件流,最初是content=res,但下载的test.xls里的内容如下图1,
            //检查了下才发现,后端对文件流做了一层封装,所以将content指向res.data即可
            //另外,流的转储属于浅拷贝,所以此处的content转储仅仅是便于理解,并没有实际作用=_=
            const content = res.data;    // 这里试试res 不行就用res.data
            const blob = new Blob([content]); //构造一个blob对象来处理数据
            const fileName = "心愿列表.xlsx";    // 下载的文件名称 可以自定义

            //对于<a>标签,只有 Firefox 和 Chrome(内核) 支持 download 属性
            //IE10以上支持blob但是依然不支持download
            if ("download" in document.createElement("a")) {
              //支持a标签download的浏览器
              const link = document.createElement("a"); //创建a标签
              link.download = fileName; //a标签添加属性
              link.style.display = "none";
              link.href = URL.createObjectURL(blob);
              document.body.appendChild(link);
              link.click(); //执行下载
              URL.revokeObjectURL(link.href); //释放url
              document.body.removeChild(link); //释放标签
            } else {
              //其他浏览器
              navigator.msSaveBlob(blob, fileName);
            }
          })
          .catch((err) => {
            console.log(err);
          });
      } else {
        this.$message.warning("请勿重复点击!");
      }
    },

以下是控制不可重复点击的代码

// 观察数据
  watch: {
    isClick() {
      if (this.isClick) {
        let timeID = setTimeout(() => {
          this.isClick = false;
          clearTimeout(timeID);
        }, 5000);
      }
    },
  },

放一张成功下载的截图

结束了~

猜你喜欢

转载自blog.csdn.net/weixin_61805851/article/details/125202070