vue文档下载并利用notify查看下载进度

在上一次讲过项目需求下载zip文件格式,还没看的小伙伴可以先看一下:
https://blog.csdn.net/m0_64573712/article/details/125382030

这次亲爱得甲方又加需求了,他们希望在下载得同时,可以查看到下载进度,因为伴随这下载内容得增大,没有明确得下载进度,用户体验很差! 这次依旧是用axios和fetch两种方法实现下载进度表

axios

获取下载进度 需要让后端设置好响应头 也就是’ContentLength’必不可少,他是后端返回得文件大小,这是要计算下载进度非常重要得一环!!但还是要注意main.ts是否存在mock导入,一旦有下载后的文件全是被破坏的!!!

利用axios封装的原生onDownloadProgress属性,该属性为一个回调方法,当axios请求将文件从服务器下载时会进行回调。接收一个回调参数,该回调参数中包含总当前下载量,总的下载量。

 axios({
      method: 'POST',
      url,
      data: params,
      responseType: 'blob', //告诉服务器想到的响应格式
      headers: { 'Content-Type': 'application/json; application/octet-stream' },
      //onDownloadProgress方法!!! 其他和之前没啥变化 并赋值给percentage用作之后得回显
      onDownloadProgress: progressEvent => {
        this.percentage = ((progressEvent.loaded / progressEvent.total) * 100) | 0;
        console.log(this.percentage);
      },
    })
      .then(res => {
        let blob = new Blob([res.data], { type: 'application/zip' }); //设置下载的内容以及格式
        const url = window.URL.createObjectURL(blob); //设置路径
        const link = window.document.createElement('a'); // 创建a标签
        link.href = url;
        link.download = '文件'; //设置文件名
        link.style.display = 'none';
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
        URL.revokeObjectURL(url); // 释放内存
      })
      .catch(function (error) {
        showMessage('下载失败', 'error');
        console.log(error);
      });

在得到下载进度后利用element-ui库中得 Notification 通知属性
代码如下:

 this.notify:any = {};
 //开始下载时等待服务器响应数据  利用this.notify获得通知框得实例 方便动态回显
 this.notify = this.$notify({
        title: '下载进度',
        offset: 130,
        dangerouslyUseHTMLString: true,
        duration: 0,
        message: `<p style="width: 200px;">正在准备数据,请等待</p>`,
        customClass: 'notify-download',
        showClose: false,
      });
      //之后需要监听percentage数值得变化 改变通知框得数值回显
      //这里watch思路写的有点乱,因为后面需求和一开始有变化,就采取了添油战术,懒得优化
     @Watch('percentage')
 	 watchPercentage() {
  	  if (this.percentage === 100) {
      this.notify.message = `<p style="width: 100px;">下载完成<span style="float: right">${this.percentage}%</span></p>`;
      this.notify.showClose = true;
      setTimeout(() => {
        this.notify.close();
     	 }, 2000);
     } else if (this.percentage > 0) {
      this.notify.message = `<p style="width: 100px;">正在下载<span style="float: right">${this.percentage}%</span></p>`;
  	  } else {
      this.notify.message = `<p style="width: 200px;">正在准备数据,请等待</p>`;
    }
  }

笔者这里之所以和正常vue的watch不同是因为 笔者所在的项目是vue2+ts需要引入特殊的vue库,大体思路没问题就好。

fetch

fetch没有自带的属性 写起来很麻烦,唯一的好处就是不用但main.ts里的mock影响到他吧- -

let size = 0;
    fetch(url, {
      body: JSON.stringify(params),
      method: 'POST',
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json',
      },
    })
      .then(res => {
        if (res.ok) {
          return res;
        } else {
          showMessage('请求下载失败', 'error');
        }
      })
      .then(res => {
        if (res) {
          this.downloadLength = res.headers.get('Content-Length');
          return res.body;
        }
      })
      .then(body => {
        if (body) {
          // eslint-disable-next-line @typescript-eslint/no-this-alias
          let this_ = this;
          const reader = body.getReader();
          return new ReadableStream({
            start(controller) {
              return pump();
              function pump(): any {
                return reader.read().then(res => {
                  //res  ({ done, value })
                  // 读不到更多数据就关闭流
                  const { done, value } = res;
                  if (done) {
                    controller.close();
                  }
                  size += value ? value.length : 0;
                  this_.percentage = ((this_.downloadLength / size) * 100) | 0;
                  // 将下一个数据块置入流中
                  controller.enqueue(value);
                  return pump();
                });
              }
            },
          });
        }
      })
      .then(stream => new Response(stream))
      .then(res => {
        res.blob().then(blob => {
          // 转化为blobURL后再通过a标签下载
          const blobUrl = window.URL.createObjectURL(blob);
          const a = window.document.createElement('a');
          a.href = blobUrl;
          a.download = '文件.zip';
          a.click();
          window.URL.revokeObjectURL(blobUrl);
        });
      })
      .catch(err => {
        showMessage('下载失败', 'error');
      });

使用fetch后 还是使用 element-ui库中得 Notification 通知属性 ,代码和上面的一样

总结

axios有封装好的回调函数,而fetch没有所以要逐层逐层回调地狱去找到 最后在用过递归函数获得当前下载量,很麻烦 ,推荐使用axios,但在使用中切记main.ts里是否存在mock!

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值