Vue使用Input大文件上传切片、修改file文件上传控件样式、清空已选择文件

219 阅读2分钟

在掘金社区发布文章,并在正文的第一句加入“我正在参加「掘金·启航计划」”

前言:

最近重构公司项目核心内容就是大文件的上传功能,文件基本上都是几个G的,着手的是原生的input标签file, 大文件我们首先考虑到一个分片上传这样的功能我们先来说一说分片的好处

好处: 分片上传的好处是将一个大请求分成多个小请求来执行,这样当其中一些请求失败后,不需要重新上传整个文件,而只需要上传失败的分片就可以了 可想而知如果不分片会造成文件的丢失,下一次上传从新开始上传,极大的浪费资源一方面给用户体验也不是很好

CSS样式:

修改前:修改前是和其他表单共用的弹窗

在这里插入图片描述

修改后:这里是另外单独的弹窗把上传事件加到确定事件上了

在这里插入图片描述

技术栈:

框架Vue2.0+Ant Design Vue组件库

代码展示:

template中

  <a-modal
    title="文件上传"
    :width="900"
    :visible="visible"
    :confirmLoading="confirmLoading"
    okText="点击上传文件"
    @ok="handleSubmit"
    @cancel="handleCancel"
  >
  <!-- UI组件库的加载效果 -->
    <a-spin :spinning="confirmLoading"> 
      <a-row>
        <a-col :span="12" :offset="6">
          <a-form :form="form" :label-col="{ span: 7 }" :wrapper-col="{ span: 10 }" has-feedback>
            <a-form-item label="模型压缩包" :label-col="{ span: 7 }" :wrapper-col="{ span: 10 }">
              <div class="ipts">
                请选择模型压缩包<input
                  v-if="!cancel_img"
                  type="file"
                  id="file"
                  name="file"
                  class="uploads"
                  @change="handleFiles"
                />
              </div>
              <!-- 文件上传的名称 -->
              <div class="fileInfo">{{ filesName }}</div>
            </a-form-item>
          </a-form>
        </a-col>
      </a-row>
    </a-spin>
  </a-modal>

script中这里面就是整个切片的逻辑思维和注释代码

export default {
  data() {
    return {
      filesName: '', //获取上传文件的名称
      cancel_img: '',
      tton: 0,
      labelCol: {
        xs: { span: 24 },
        sm: { span: 6 },
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 16 },
      },
      // 机构行样式
      labelCol_JG: {
        xs: { span: 24 },
        sm: { span: 3 },
      },
      wrapperCol_JG: {
        xs: { span: 24 },
        sm: { span: 20 },
      },
    }
  },
  methods: {
    // 获取上传文件的名称
    handleFiles(event) {
      this.filesName = event.target.files[0].name
    },
    save() {
      // 每个文件切片大小定为1M(1024*1024字节)(需要跟服务器协商好)
      var BYTES_PER_SLICE = (1 << 20) * 100 //这里定义的是每个包分的是100MB
      // 已发送的数量
      var hasSendNum = 0
      // 总切片数
      var totalSlices
      this.tton == 1
      this.confirmLoading = true //loading加载
      // 拿出选中的第一个文件
      var file = document.getElementById('file').files[0]
      // 文件的总字节数
      var totalSize = file.size
      // 当前片数
      var index = 0
      // 分片的开始、结束(不含)
      var start, end
      // 文件名
      var fileName = file.name
      // 初始化已发送数量为0
      hasSendNum = 0
      // 计算文件切片总数(向上取整)
      totalSlices = Math.ceil(file.size / BYTES_PER_SLICE)
      // 不断循环将切片上传
      while (index < totalSlices) {
        start = index * BYTES_PER_SLICE
        end = start + BYTES_PER_SLICE
        var slice = file.slice(start, end) //切割文件
        this.handleChangeupload(slice, index++, fileName, totalSlices, totalSize)
      }
    },
    handleChangeupload(slice, index, fileName, totalSlices, totalSize) {
      var retry = 1
      var FormDate = new FormData()
      FormDate.append('totalSlices', totalSlices) //总数
      FormDate.append('index', index) //当前数
      FormDate.append('totalSize', totalSize) //字节数
      FormDate.append('filename', fileName) //文件名
      FormDate.append('file', slice) //文件流
      addThreeDUrl(FormDate).then((res) => {//调用上传接口
        if (res.code == 200) {
          this.$message.success('上传成功')
          this.confirmLoading = false //关闭loading加载
          this.visible = false //关闭弹窗
          //nextTick 函数是在下一次dom更新后回调,
          //这就可以实现先执行的上面的代码,让input[file]节点消失,
          //然后再dom更新后回调该函数,又执行了让input[file]节点显示,这样就实现了刷新
          this.cancel_img = true
          this.$nextTick(() => {
            this.cancel_img = false
          })
          this.filesName = '' //清除上传文件名称
        } else {
          this.$message.console.error('上传失败')
          this.confirmLoading = false //关闭loading加载
        }
      })
    },
    // 点击上传文件按钮
    handleSubmit() {
      if (this.filesName != '') {
        this.save()
      } else {
        this.$message.error('请选择模型压缩包再点击上传')
      }
    },
    // 取消按钮
    handleCancel() {
      this.cancel_img = true
      this.$nextTick(() => {
        this.cancel_img = false
      })
      this.filesName = '' //清除上传文件名称
      this.visible = false
    },
  },
}

CSS样式覆盖原有的样式

.ipts {
  width: 210px;
  height: 128px;
  padding: 4px 10px;
  line-height: 127px;
  position: relative;
  border: 1px solid #999;
  text-decoration: none;
  color: #333;
  background-color: #fafafa;
  text-align: center;
  border: 1px dashed #999;
  border-radius: 5px;
  cursor: pointer;
}
.uploads {
  position: absolute;
  overflow: hidden;
  right: 0;
  top: 0;
  opacity: 0;
  width: 100%;
  height: 100%;
  cursor: pointer;
}

总结:

以上就是所有内容和代码,欢迎大家指教