vue axios上传多个附件并单独显示进度条

就是把input type=file的opacity置为0,然后在底下放有样式的元素,然后通过axios的 onUploadProgress 的参数total和loaded显示进度,当然要在后端返回成功之后再把进度置为100%。然后监听一下文件数组,当所有进度都为1的时候就表示完成了。

<template>
  <div id="upload">
    <div class="bg-whi">
      <div class="extendex-top" ref="top">
        <div class="top-box">
          <div class="g-title">上传附件</div>
        </div>
      </div>
      <div class="pub-con" ref="bg">
        <div class="input-zone">
          <span class="upload-des">选择文件(不超过30m)</span>
          <input
            class="input"
            type="file"
            name="file"
            value
            placeholder="请选择文件"
            ref="file"
            v-show="canSub"
            @change="changeFile()"
            accept="application/pdf;image/*;application/mp4"
          />
        </div>
      </div>
      <div class="pad">
        <div class="file-list">
          <div class="file-item" v-for="(item,index) in fileArray" :key="index">
            <p>
              {{item.name}}
              <img
                src="../../assets/image/upload-delete.png"
                @click="deleteFile(index)"
                v-show="item.progress==0"
                class="upload-delete"
              />
            </p>
            <div class="progress-container" v-show="item.progress!=0">
              <div class="progress-wrapper">
                <div class="progress-progress" :style="'width:'+item.progress*100+'%'"></div>
              </div>
              <div class="progress-rate">
                <span v-if="item.progress!=1">{{(item.progress*100).toFixed(0)}}%</span>
                <img v-else class="upload-success" src="../../assets/image/upload-success.png" />
              </div>
            </div>
          </div>
        </div>
        <div class="tips">支持上传jpg、png、ppt、pptx、MP3、MP4格式的附件!</div>
        <div class="btn-container">
          <button class="btn btn-blue" v-if="fileArray.length&&canSub" @click="upload">开始上传</button>
          <button class="btn btn-gray" v-else>开始上传</button>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
import serverUrl from "../../utils/common.js"; //取出公共url
import axios from "axios";
import { Message } from "element-ui";
export default {
  data() {
    return {
      fileArray: [],//文件数组
      canSub: true,
      finish: false,
    };
  },
  watch: {
    //监听文件列表数组,当全部完成时给出提示并跳转页面
    fileArray: {
      handler(newValue, oldValue) {
        console.log(newValue);
        var finish = newValue.find(function(currentValue, index) {
          return currentValue.progress != 1;
        });
        if (finish === undefined && this.fileArray.length) {
          this.finish = true;
          Message({
            message: "上传成功",
            type: "success",
            duration: 1 * 1000,
            customClass: "message-box",
            iconClass: "message-icon"
          });
          this.$router.go(-1);
        }
      },
      deep: true
    }
  },
  methods: {
    //删除指定文件
    deleteFile(index) {
      this.fileArray.splice(index, 1);
      var fileTarget = this.$refs.file;
      fileTarget.value = "";
    },
    //选择文件
    changeFile() {
      var fileTarget = this.$refs.file;
      if (this.fileArray.length >= 10) {
        Message({
          message: "最多只能上传十个附件",
          type: "success",
          duration: 1 * 1000,
          customClass: "message-box",
          iconClass: "message-icon"
        });
        fileTarget.value = "";
      } else {
        if (fileTarget.files[0].size > 31457280) {
          Message({
            message: "文件大小不能超过30m",
            type: "success",
            duration: 1 * 1000,
            customClass: "message-box",
            iconClass: "message-icon"
          });
          fileTarget.value = "";
        } else {
            //避免重复的文件
          if (
            this.fileArray.indexOf(fileTarget.files[0]) == -1 ||
            this.fileArray.length == 0
          ) {
            var fileItem = Object.assign(fileTarget.files[0], { progress: 0 });
            this.fileArray.push(fileItem);
          }else{
            fileTarget.value = "";
          }
        }
      }
    },
    //上传
    upload() {
      if (this.docLength >= 10) {
        Message({
          message: "最多只能上传十个附件",
          type: "success",
          duration: 1 * 1000,
          customClass: "message-box",
          iconClass: "message-icon"
        });
      } else {
        this.canSub = false;
        var myArr = this.fileArray;
        var vm = this;
        let user = localStorage.user;
        user = JSON.parse(user);
        let token = user.token;
        let id = this.$route.params.id;
        //循环文件数组挨个上传
        myArr.forEach((element, index) => {
          var config = {
            headers: { "Content-Type": "multipart/form-data" },
            onUploadProgress: function(e) {
              //属性lengthComputable主要表明总共需要完成的工作量和已经完成的工作是否可以被测量
              //如果lengthComputable为false,就获取不到e.total和e.loaded
              if (e.lengthComputable) {
                var rate = e.loaded / e.total; //已上传的比例
                console.log(index, e.loaded, e.total, rate);
                if (rate < 1) {
                  //这里的进度只能表明文件已经上传到后台,但是后台有没有处理完还不知道
                  //因此不能直接显示为100%,不然用户会误以为已经上传完毕,关掉浏览器的话就可能导致上传失败
                  //等响应回来时,再将进度设为100%
                  myArr[index].progress = rate;
                  vm.$set(vm.fileArray, index, myArr[index]);
                } else {
                  myArr[index].progress = 0.99;
                  vm.$set(vm.fileArray, index, myArr[index]);
                }
              }
            }
          };
          var data = myArr[index];
          var myForm = new FormData();
          myForm.append("file", data);
          myForm.append("courseId", id);
          axios.defaults.headers.post["token"] = token;
          axios
            .post(serverUrl + "mobile/course/uploadFile", myForm, config)
            .then(function(res) {
              if (res.data.code == 0) {
                //后端返回成功,将进度置为100%
                myArr[index].progress = 1;
                vm.$set(vm.fileArray, index, myArr[index]);
                console.log(vm.fileArray, index);
              } else {
                alert(JSON.stringify(res.data));
              }
            })
            .catch(function(err) {
              console.log(err);
            });
        });
      }
    },
  }
};
</script>
<style scoped>
.extendex-top {
  background: none;
  box-shadow: none;
}
.bg-whi {
  min-height: 100vh;
  box-sizing: border-box;
}
.top-box {
  background: url(../../assets/image/detail-bg.png) top no-repeat;
  background-size: 100%;
}
.pub-con {
  width: 100%;
  box-sizing: border-box;
  background: url(../../assets/image/detail-bg.png) top no-repeat;
  background-size: 100%;
  text-align: center;
  position: relative;
}
.input-zone {
  width: 14.13rem;
  height: 2.75rem;
  line-height: 2.75rem;
  background: url("../../assets/image/upload.png") no-repeat 0.63rem center
    #ffffff;
  background-size: 2.13rem;
  border-radius: 1.38rem;
  border: 0.06rem solid rgba(90, 88, 199, 1);
  margin: 2.06rem auto;
  position: relative;
  color: #5a58c7;
  font-size: 0.88rem;
  padding-left: 2.5rem;
  box-sizing: border-box;
}
.input {
  opacity: 0;
  width: 100%;
  height: 100%;
  position: absolute;
  left: 0;
  top: 0;
  z-index: 2;
}
.pad {
  padding: 0.5rem 1.7rem 0 1.7rem;
  font-size: 0.88rem;
}
.btn-container {
  margin: 0.69rem auto;
  text-align: center;
}
.btn-container .btn {
  width: 10.56rem;
  height: 2.5rem;
  border-radius: 1.25rem;
  border: none;
  color: #ffffff;
}
.btn-container .btn.btn-gray {
  background: rgba(201, 201, 201, 1);
}
.btn-container .btn.btn-blue {
  background: linear-gradient(
    180deg,
    rgba(128, 137, 229, 1) 0%,
    rgba(87, 84, 196, 1) 100%
  );
  font-size: 1rem;
}
.tips {
  margin-top: 1.69rem;
}
.file-list {
  font-size: 0.88rem;
  color: #5a5cc6;
}
.file-list .file-item {
  margin-top: 0.63rem;
}
.file-list .file-item p {
  line-height: 1.25rem;
  position: relative;
}
.file-list img {
  width: 1.25rem;
  cursor: pointer;
}
.file-list img.upload-delete {
  position: absolute;
  bottom: 0;
  margin: 0 auto;
  margin-left: 1rem;
}
.progress-wrapper {
  position: relative;
  height: 0.5rem;
  border: 0.06rem solid rgba(92, 91, 200, 1);
  border-radius: 1px;
  box-sizing: border-box;
  width: 87%;
}
.progress-wrapper .progress-progress {
  position: absolute;
  left: 0;
  top: 0;
  height: 100%;
  width: 0%;
  border-radius: 1px;
  background-color: #5c5bc8;
  z-index: 1;
}
.progress-rate {
  font-size: 14px;
  height: 100%;
  z-index: 2;
  width: 12%;
  display: flex;
  justify-content: center;
  align-items: center;
}
.progress-rate span {
  display: inline-block;
  width: 100%;
  text-align: right;
}
.progress-container {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.file-list img.upload-success {
  margin-left: 0;
}
</style>

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值