elementui-vue上传文件带进度条

2,952 阅读2分钟

1、使用elementui上传文件自定义进度条

  • 满足上传文件
  • 上传文件前显示文字,过程中显示进度条,上传完后显示文字
  • 上传过程中可以取消上传
  • 上传限制大小,格式,上传文件个数

image.png

image.png 思路:

  • 点击上传后,显示进度条,禁止点击;点击取消,可以点击;上传完成,进度条消失,可以点击;
  • 上传完成后,需要接口返回处理内容,上传完成设置为90%,接口返回后设置为100%
  • 上传到90%就不能再取消

uploadFile.vue

<template>
  <div class="update-file-container">
    <!-- 上传 -->
    <div class="upload-content">
      <el-upload
        class="upload-demo"
        ref="upload"
        :disabled="percentage > 0"
        drag
        action=""
        :limit="1"
        accept=".xlsx"
        :file-list="fileList"
        :show-file-list="false"
        :on-exceed="handleExceed"
        :before-upload="beforeUpload"
        :http-request="uploadFile"
      >
        <i class="el-icon-upload"></i>
        <div v-if="!isShowProgress" class="el-upload-text">
          <div class="click-upload-text">点击或将文件拖拽到这里上传</div>
          <div class="file-text">文件大小不应超过100M,支持扩展名:.xlsx</div>
        </div>
        <div v-if="isShowProgress" class="el-upload-progress">
          <!-- 进度条上方文件名 -->
          <div class="upload-filename">
            <div>{{ filename }}</div>
            <div :class="percentage >= 90 ? 'noneimg' : 'blockimg'">
              <i class="el-icon-circle-close" @click="handleRemove"></i>
            </div>
          </div>
          <!-- 进度条 -->
          <el-progress
            style="width: 400px"
            :percentage="percentage"
            :format="format"
            :text-inside="true"
            :color="customColor"
            :stroke-width="4"
          >
          </el-progress>
          <!-- 进度条数字 -->
          <div class="percentage-text">已上传{{ percentage }}%…</div>
        </div>
      </el-upload>
    </div>
  </div>
</template>

<script>
// 取消上传
let cancel = null
export default {
  name: 'uploadfile',
  data() {
    return {
      templateId: this.$route.params.templateId,
      // 是否显示进度条
      isShowProgress: false,
      // 文件
      fileList: [],
      // 文件名
      filename: '',
      // 进度条
      percentage: 0,
      // 进度条颜色
      customColor: '#910E0E',
    }
  },
  methods: {
    // 文件超出限制个数时提醒
    handleExceed() {
      this.$message.warning(`当前限制选择 1 个文件,请删除后继续上传`)
    },
    // 上传前格式验证
    beforeUpload(file) {
      const fileName = file.name
      const fileType = fileName.split('.').pop()
      const fileSize = file.size / 1024 / 1024
      if (fileType !== 'xlsx') {
        this.$message.warning('您好,文件格式不对,请调整后重新上传')
        return false
      }
      if (fileSize > 100) {
        this.$message.warning('您好,文件过大,请调整后重新上传')
        return false
      }
    },
    // 上传文件
    uploadFile(item) {
      this.isShowProgress = true
      // 上传需要的传参
      let fileList = item.file
      let form = new FormData()
      form.append('file', fileList)
      // 添加参数,比如templateId
      form.append('templateId', this.templateId)
      // 进度条
      const uploadProgress = progressEvent => {
        this.filename = item.file.name
        this.percentage = Number(
          ((progressEvent.loaded / progressEvent.total) * 100).toFixed(2)
        )
        // 当上传成功时设为90%,等接口返回结果设为100%
        if (this.percentage >= 90) {
          this.percentage = 90
        }
      }
      this.$http.fileUpdate
        .uploadFile(form, uploadProgress, function (c) {
          // 取消上传时,取消接口上传
          cancel = c
        })
        .then(res => {
          if (res && res.code === 0) {
            this.percentage = 100
            // 接口返回后进行的操作
          } else if (res && res.code === 500) {
            // 上传失败
            this.hiddenProgress()
            this.$message.warning('您好,文件上传失败,请重新上传')
          }
        })
        .catch(err => {
          console.error(err)
        })
    },
    // 清空数据
    hiddenProgress() {
      this.fileList = []
      this.isShowProgress = false
      this.percentage = 0
      this.filename = ''
    },
    // 取消上传
    handleRemove() {
      setTimeout(() => {
        cancel('cancel')
        this.$message.warning(`取消上传成功`)
        this.$refs.upload.abort()
        this.hiddenProgress()
      })
    },
    // 进度条内容为空
    format() {
      return ''
    },
  },
  // 离开页面时取消当前上传操作
  beforeDestroy() {
    if (this.percentage > 0) {
      cancel('cancel')
      this.$refs.upload.abort()
      this.hiddenProgress()
    }
  },
}
</script>

<style scoped lang="scss">
.update-file-container {
  background: #ffffff;
  padding: 28px 24px;
  min-height: 956px;
  // 上传
  .upload-content {
    margin-top: 72px;
    display: flex;
    justify-content: center;
    ::v-deep .el-upload-dragger {
      width: 560px;
      height: 259px;
      border-radius: 4px;
      border: 2px dashed rgba(0, 0, 0, 0.12);
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      .el-upload-text {
        font-size: 14px;
        font-family: PingFangSC-Regular, PingFang SC;
        font-weight: 400;
        line-height: 20px;
        padding-top: 16px;
        .click-upload-text {
          color: rgba(0, 0, 0, 0.84);
        }
        .file-text {
          color: rgba(0, 0, 0, 0.24);
          margin-top: 8px;
        }
      }
    }
    .el-upload-progress {
      display: flex;
      flex-direction: column;
      align-items: center;
      width: 400px;
      font-family: PingFang SC;
      font-size: 14px;
      padding-top: 16px;
      .upload-filename {
        display: flex;
        justify-content: space-between;
        width: 400px;
        font-weight: 500;
        color: rgba(0, 0, 0, 0.6);
        .noneimg {
          display: none;
        }
        .blockimg {
          display: block;
        }
      }
      .percentage-text {
        display: flex;
        justify-content: flex-start;
        width: 400px;
        font-weight: 400;
        color: rgba(0, 0, 0, 0.24);
      }
    }
  }
}
</style>

接口:

// 上传文件
export function uploadFile(data, onUploadProgress, cancelToken) {
    return axios({
        url: '......',
        method: 'post',
        data,
        onUploadProgress
    }, "", "", cancelToken)
}

拦截请求时操作:

import axios from 'axios'
export default (options, headers, responseType, cancel) => {
  return new Promise((resolve, reject) => {
    const CancelToken = axios.CancelToken;
    
    // 创建 axios对象,并设置拦截器
    const $axios = axios.create({
      baseURL: config.BASE_API_URL,
      headers: headers || config.HEADER,
      responseType: responseType || 'json',
      // 取消操作
      cancelToken: cancel ? new CancelToken(cancel) : new CancelToken(function (c) {})
    })
    // 请求拦截器
    $axios.interceptors.request.use(
      config => {
        return config
      },
      request => {
        return request
      },
      error => {
        return Promise.reject(error)
      }
    )
    // 响应拦截器
    $axios.interceptors.response.use(
      response => {
        ......
      },
      error => {
        //主动中断请求
        if (error.message && error.message === 'cancel') {
          return
        }
        ......
      }
    )
    // 处理请求
    $axios(options).then(response => {
      resolve(response)
    }).catch(error => {
      reject(error)
    })
  })
}