vue上传多个文件 获取进度条实时刷新进度

发布时间:2024年01月09日
<template>
  <div>
    <Button
      type="primary"
      style="margin-right: 14px;"
      @click="uploadFile"
      >上传</Button
    >
    <input
      type="file"
      id="importFile"
      @change="checkedFile"
      style="display: none"
      accept="*"
      multiple
    />
   </div>
     <div v-for="(item, index) in postImgList" :key="index">
       {{ item.name }}
     </div>
     <div class="class_percent">
       <Progress :percent="percent" :stroke-color="['#108ee9', '#87d068']" />
     </div>
</template>
export default {
  data() {
    return {
      postImgList: [],
      percent: 0
    };
  },
  methods: {
	uploadFile() {
      const loader = document.getElementById("importFile");
      loader.click();
    },
   	checkedFile({ target }) {
      this.postImgList = Array.from(target.files);
      if (this.postImgList.length === 0) { //如果没文件点击取消不需要调用接口
        return
      };
      this.postImgList.forEach(item => {
        item.percent = 0;  // 每一条进度
        const fileSize = item.size / 1024 / 1024; // 转换为MB
        if (fileSize > 50) {  // 判断文件大小是否超过50
          this.$Message.warning(`${item.name}文件大小超过50M啦,请重新选择`);
          return false;
        };
      });
      this.upload();
    },
       // 上传按钮
    upload() {
      const formData = new FormData();
      formData.append("key", "需要传的参数");
      this.postImgList.forEach((item) => {
        formData.append("file", item);
      });
      const msg = this.$Message.loading({
        content: "正在上传...",
        duration: 0,
        closable: true,
      });
      this.$api.接口(formData, {
        onUploadProgress: e => {
          // lengthComputable:布尔值,表示加载的总量是否可以计算,默认是false。
          // loaded:整数,表示已经加载的量,默认是0。
          // total:整数,表示需要加载的总量,默认是0。
          if (e.lengthComputable) {
            this.percent = Math.round((e.loaded * 100) / e.total) == 100 ? 99 : Math.round((e.loaded * 100) / e.total);
            if (this.percent === 100) {
              setTimeout(msg, 5);
            }
          };
        }
      }).then((res) => {
        setTimeout(msg, 5);
        if (res.error !== "error") {
          this.$Message.success("上传成功");
          this.percent = 100;
          this.getUavRefPage();
        }
      }).catch(() => {
        setTimeout(msg, 5);
      });
    },
    // 更新上传进度  没用到
    updateFileProgress(file, progress) {
      file.progress = progress;
      if (progress === 100) {
        setTimeout(() => {
          this.fileList.splice(this.fileList.indexOf(file), 1);
        }, 1000);
      }
    },
  }
}
// e.loaded和e.total属性属于 JavaScript 中的 ProgressEvent 对象,在文件上传期间会被浏览器不断地更新,以确保上传进度得到及时的反馈。在 Axios 中,需要在上传请求中通过onUploadProgress属性传入该对象,比如:
axios.post('/upload', formData, {
  onUploadProgress: e => {
    console.log('已上传字节数:' + e.loaded);
    console.log('总字节数:' + e.total);
  }
});
// 在这里,onUploadProgress 是一个回调函数,该函数会在文件上传过程中被反复调用。而e 则是个ProgressEvent 对象,包含了与上传进度相关的一些属性。其中,e.loaded 表示上传的已完成的字节数,e.total 表示总字节数。需要注意的是,不同的浏览器和操作系统可能会返回不同的属性值。如果你使用的是 Vuejs,也可以使用axios.create 方法在组件内部创建一个自定义的Axios实例,并设置默认的onUploadProgress 回调:
export default {
  // 其他代码
  methods: {
    upload() {
      // 创建自定义 Axios 实例
      const instance = axios.create({
        onUploadProgress: e => {
          console.log('已上传字节数:' + e.loaded);
          console.log('总字节数:' + e.total);
        }
      });

      // 发出请求
      instance.post('/upload', formData);
    }
  }
}
这样,该组件内部所有的请求都会默认使用 instance 实例,且会默认携带 onuploadProgress
回调函数。

以下是chat GPT给的

<template>
  <div>
    <input type="file" ref="fileInput" multiple @change="uploadFiles">
    <ul>
      <li v-for="(file, index) in fileList" :key="index">
        {{ file.name }}
        <Progress :percent="file.progress" v-if="file.progress !== 100"/>
        <Icon name="ios-close" class="delete-icon" @click.prevent="removeFile(index)" />
      </li>
    </ul>
  </div>
</template>

<script>
import { Upload, Progress, Icon } from 'view-design';
import axios from 'axios';
export default {
  components: { Upload, Progress, Icon },
  data() {
    return {
      fileList: []
    };
  },
  methods: {
    // 上传文件
    uploadFiles() {
      // 获取选择的文件
      const files = this.$refs.fileInput.files;

      // 遍历每个文件进行上传
      for (let i = 0; i < files.length; i++) {
        const file = files[i];

        // 创建新的文件对象
        const newFile = {
          name: file.name,
          progress: 0,
          file: file,
          cancelToken: null
        };

        // 添加到文件列表
        this.fileList.push(newFile);

        // 创建FormData对象实现上传
        const formData = new FormData();
        formData.append('file', file);

        // 执行上传操作
        const cancelTokenSource = axios.CancelToken.source();
        axios.post('/upload', formData, {
          cancelToken: cancelTokenSource.token,
          onUploadProgress: e => {
            if (e.lengthComputable) {
              const percent = Math.round((e.loaded * 100) / e.total);
              this.updateFileProgress(newFile, percent);
            }
          }
        })
        .then(response => {
          this.updateFileProgress(newFile, 100);
        })
        .catch(error => {
          if (axios.isCancel(error)) {
            console.log('上传已取消:', file.name);
          }
        });
        newFile.cancelToken = cancelTokenSource;
      }

      // 清空选择的文件
      this.$refs.fileInput.value = null;
    },

    // 更新上传进度
    updateFileProgress(file, progress) {
      file.progress = progress;
      if (progress === 100) {
        setTimeout(() => {
          this.fileList.splice(this.fileList.indexOf(file), 1);
        }, 1000);
      }
    },

    // 删除文件
    removeFile(index) {
      const file = this.fileList[index];
      if (file) {
        if (file.cancelToken) {
          file.cancelToken.cancel(`用户取消上传:${file.name}`);
        }
        this.fileList.splice(index, 1);
      }
    }
  }
};
</script>

<style>
.delete-icon {
  margin-left: 10px;
  font-size: 14px;
  color: #f00;
  cursor: pointer;
}
</style>
文章来源:https://blog.csdn.net/weixin_46113850/article/details/135474144
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。