下载文件带进度条

发布时间 2023-03-28 16:58:41作者: 小万子呀
<template>
  <el-dialog title="批量下载" :visible.sync="isShow" width="1000" :before-close="handleClose">
    <div class="downBox">
      <div class="downTop">
        <span>文件下载</span>
        <span style="margin-left: 15px;"><el-button type="success" @click="loadDown">开始下载</el-button></span>
      </div>
      <div class="fileItem" v-for="v in imgArr" :key="v.id">
        <span>{{ v.url }}</span>
        <span><el-progress :percentage="v.progress"></el-progress></span>
      </div>
      <div class="page_box">
        <span></span>
        <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" background
          :current-page="page.current" :page-sizes="[10, 20, 50, 100]" :page-size="page.size"
          layout="total, sizes, prev, pager, next" :total="imgArrAll.length">
        </el-pagination>
      </div>
    </div>
  </el-dialog>
</template>

<script>
const path = require('path')
export default {
  data () {
    return {
      isShow: false,
      imgArrAll: [], // 全部数据
      imgArr: [], // 分页数据
      page: {
        size: 100,
        current: 1,//当前页码
      },
      dowmFile:[],//正在下载的数据
      downNum:5,//同时下载个数
    }
  },
  methods: {
    //模拟获取文件列表
    getFolderImages () {
      // 获取图片文件夹下所有png格式的文件路径
      const images = require.context('./img', true, /\.(png|jpe?g|gif|svg)(\?.*)?$/)
      // 转换成URL格式并存储到数组中
      this.imgArrAll = images.keys().map((key, index) => {
        return {
          url: new URL(images(key), location.origin).href,
          progress: 0,
          id: index,
        }
      })
      this.showTable()
    },
    // 准备下载的数据
    loadDown(){
      if(this.imgArrAll.length>0){
        let allPage = Math.floor(this.imgArrAll.length / this.downNum)
        this.dowmFile = this.imgArrAll.slice(0,this.downNum)
        this.dowmFile.map((v,i)=>{
          this.downloadFile(v)
        })
      }
    },
    // 下载文件
    downloadFile (val) {
      const self = this
      const x = new XMLHttpRequest()
      x.open('GET', val.url, true)
      x.responseType = 'blob'
      x.onload = function () {
        const herf = window.URL.createObjectURL(x.response)
        const a = document.createElement('a')
        a.href = herf
        a.download = val.url
        a.click()
        if (navigator.msSaveBlob) {
          navigator.msSaveBlob(x.response, title)
        }
      }
      // todo: 添加下载进度
      x.onprogress = (event) =>{
        // 只有 e.lengthComputable 为真,才会有进度条的信息
        if (event.lengthComputable) {
          var percentComplete = event.loaded / event.total
          var progress = parseInt(percentComplete * 100)
          self.shipvalue = progress++
          this.imgArrAll.map(v=>{ // 改变数据源的进度
            if(v.id == val.id){
              v.progress = self.shipvalue
            }
          })
          this.imgArr.map(v=>{ // 改变表格显示的进度
            if(v.id == val.id){
              v.progress = self.shipvalue
            }
          })
          // 进度
        }
      }
      x.onreadystatechange = (e) => {
        if (x.readyState === 4) { // 4 = "loaded"
          if (x.status === 200) { // 200 = "OK"
            // 下载成功 
            this.downSuccess(val)
          } else {
            self.$message.error('下载失败:' + x.statusText)
          }
        }
      }
      x.send()
    },
    // 下载成功之后继续操作 - 每当完成一个下载就继续一个下载
    downSuccess(){
      this.downloadFile(this.imgArrAll.find(v=> v.progress == 0))
    },
    //计算分页表格显示数据
    showTable () {
      this.imgArr = []
      this.imgArr = this.imgArrAll.slice((~~this.page.size) * (~~this.page.current - 1), (~~this.page.size * ~~this.page.current))
    },
    showDialogs () { this.isShow = true, this.getFolderImages() },
    handleClose () { this.isShow = false },
    handleSizeChange (e) { // 改变总条数
      this.page.size = e
      this.showTable()
    },
    handleCurrentChange (e) { // 改变页码
      this.page.current = e
      this.showTable()
    },
  }
}
</script>

<style lang="less" scoped>
.downBox {
  .downTop {
    height: 72px;
    background: #FFFFFF;
    border: 1px solid #DEDEDE;
    display: flex;
    align-items: center;
    padding: 0 16px;
  }

  .fileItem {
    border: 1px solid #DEDEDE;
    border-top: none;
    display: flex;
    align-items: center;
    padding: 13px 16px;
    box-sizing: border-box;
    justify-content: space-between;
    color: #666666;

    span:nth-child(2) {
      display: inline-block;
      width: 170px;
    }
  }

  .page_box {
    margin-top: 30px;
    display: flex;
    align-items: center;
    justify-content: space-between;
  }
}


/deep/.el-dialog__header {
  border-bottom: 1px solid #F0F0F0 !important;
}

/deep/.el-button--success {
  background-color: #02D48E !important;
  border-color: #02D48E !important;
}
</style>