vue-element-admin 上传进度条

前言

今天分享一个在 vue-element-admin 中使用的上传组件,使用 elementUI 仪表盘形进度条,可以上传图片、视频。图片、视频尺寸根据传入的参数改变。

效果

报错 Invalid prop: custom validator check failed for prop "percentage".

出现这个错误的原因,并不是因为 dom 已经渲染完成了,而数据还没回来。而是因为 percentage 超出正常取值(0~100)范围。

因为人为的控制进度,所以 percentage 会出现负数现象。

控制进度是因为,后端处理上传数据需要时间,前端已经传完了,但是资源地址返回会慢一些。如果进度条过早走到 100% 而资源地址还没拿到显示不出来,会让用户迷惑。

// 上传进度调用方法实现
xhr.upload.onprogress = function(evt) {
  // evt.total是需要传输的总字节,evt.loaded是已经传输的字节。如果evt.lengthComputable不为真,则evt.total等于0
    if (evt.lengthComputable) {
      // 进度条限制 上传时永远不能达到100% 最大95% 除非收到后端返回值 才设置为100%
      $v.percentage = Math.floor(evt.loaded / evt.total * 100) - 5
      console.log($v.percentage)
    }
}

找到问题后就很好解决了

$v.percentage < 0 ? $v.percentage = 0 : $v.percentage

源码

<template>
  <div>
    <el-upload
      v-if="type=='img'"
      :multiple="false"
      class="avatar-uploader"
      action="file/cp-file/upload"
      :show-file-list="false"
      :before-upload="beforeUpload"
    >
      <img v-if="sourceURL" :src="sourceURL" :class="['avatar',wh]">
      <i v-else :class="['el-icon-plus','avatar-uploader-icon',wh]" />
    </el-upload>

    <el-upload
      v-if="type=='video'"
      :multiple="false"
      class="avatar-uploader"
      action="file/cp-file/upload"
      :show-file-list="false"
      :before-upload="beforeUpload"
    >
      <video v-if="sourceURL" :poster="postUrl" :src="sourceURL" autoplay loop>
        您的浏览器不支持 video 标签。
      </video>
      <i v-else :class="['el-icon-plus','avatar-uploader-icon',wh]" />
    </el-upload>

    <!-- 上传进度条 -->
    <!-- Invalid prop: custom validator check failed for prop "percentage". -->
    <el-progress v-if="showProgress" type="dashboard" :percentage="percentage" :color="colors" />
  </div>
</template>

<script>
// import { fileUpload } from '@/api/common'
import { getToken } from '@/utils/auth'

export default {
  name: 'FileUpload',
  props: {
    name: {
      type: String,
      default: ''
    },
    fileUrl: {
      type: String,
      default: ''
    },
    postUrl: {
      type: String,
      default: ''
    },
    wh: {
      type: String,
      default: ''
    },
    type: {
      type: String,
      default: 'img'
    }
  },
  data() {
    return {
      percentage: 0,
      colors: [
        { color: '#f56c6c', percentage: 20 },
        { color: '#e6a23c', percentage: 40 },
        { color: '#5cb87a', percentage: 60 },
        { color: '#1989fa', percentage: 80 },
        { color: '#6f7ad3', percentage: 100 }
      ],
      showProgress: false,
      sourceURL: ''
    }
  },
  watch: {
    fileUrl() {
      this.sourceURL = this.fileUrl
    }
  },
  mounted() {
    this.sourceURL = this.fileUrl
  },
  methods: {
    // 上传预处理
    beforeUpload(file) {
      if (this.type === 'img') {
        const isLt20M = file.size / 1024 / 1024 < 20
        if (file.type.indexOf('image/') === -1) {
          this.$message.error('文件格式错误,请上传图片类型,如:JPG,PNG后缀的文件。')
        } else {
          if (!isLt20M) {
            this.$message.error('上传图片大小不能超过 20MB!')
          } else {
            this.handleUpload(file)
          }
        }
      } else {
        // 视频上传
        const isLt100M = file.size / 1024 / 1024 < 100
        if (file.type.indexOf('video/') === -1) {
          this.$message.error('文件格式错误,请上传MP4格式的视频。')
        } else {
          if (!isLt100M) {
            this.$message.error('上传视频大小不能超过 100MB!')
          } else {
            this.handleUpload(file)
          }
        }
      }
    },
    handleUpload(file) {
      var $v = this
      $v.percentage = 0
      $v.showProgress = true
      var form = new FormData() // FormData 对象
      form.append('file', file) // 文件对象

      var xhr
      xhr = new XMLHttpRequest()// XMLHttpRequest 对象
      // Token不能为空
      xhr.open('post', 'http://xxxxx/file/cp-file/upload', true) // post方式,url为服务器请求地址,true 该参数规定请求是否异步处理。

      xhr.setRequestHeader('User-Token', getToken())

      xhr.onload = function(evt) { // 请求完成
        // 服务器接收完文件返回的结果
        var res = JSON.parse(evt.target.responseText)
        if (res.code === 200) {
        // 上传成功
          $v.percentage = 100
          $v.sourceURL = res.data.url
          $v.$emit('handleUploadSuccess', $v.name, res.data)
          $v.showProgress = false
        }
      }
      xhr.onerror = function() {
        $v.$message.error('上传失败')
      }
      // 上传进度调用方法实现
      xhr.upload.onprogress = function(evt) {
        // evt.total是需要传输的总字节,evt.loaded是已经传输的字节。如果evt.lengthComputable不为真,则evt.total等于0
        if (evt.lengthComputable) {
          // 进度条限制 上传时永远不能达到100% 最大95% 除非收到后端返回值 才设置为100%
          $v.percentage = Math.floor(evt.loaded / evt.total * 100) - 5
          $v.percentage < 0 ? $v.percentage = 0 : $v.percentage
        }
      }
      xhr.send(form) // 开始上传,发送form数据
    }
  }
}

</script>

<style lang="scss">
// undo 如有 scoped 则父组件样式无法渲染?
.avatar-uploader .el-upload {
    border: 1px dashed #d9d9d9;
    border-radius: 6px;
    cursor: pointer;
    position: relative;
    overflow: hidden;
  }

  .avatar-uploader .el-upload:hover {
    border-color: #409EFF;
  }

  //资讯话题分类
  .newTypeWidthHeight{
    width: 159px;
    height: 207px;
    line-height: 207px;
  }

  //会员权益身份icon样式
  .memberPriceWidthHeight {
    width: 100px;
    height: 100px;
    line-height: 100px;
  }

  //资讯封面
  .newImgWidthHeight{
    width: 270px;
    height: 180px;
    line-height: 180px;
  }

  //视频封面
  .newVideoWidthHeight{
    width: 640px;
    height: 360px;
    line-height: 360px;
  }

  .avatar {
    display: block;
  }

  video{
    width: 640px;
    height: 360px;
    // 拉伸以适应内容框,解决视频黑边
    object-fit: cover;
  }

  .avatar-uploader-icon {
    font-size: 28px;
    color: #8c939d;
    text-align: center;
  }

</style>

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Irene1991

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值