vue + element 实现文件上传

当时写文件上传是一件让人难受的事情,测试了很久,终于完成。
写完之后超超超超超超级开心~
效果如下图:
在这里插入图片描述
功能描述:

  1. 点击添加,可以增加多条,如下图:
    在这里插入图片描述
    2. 点击删除,顾名思义,删掉这一行。
    3. 点击照片后面的 x 号,进行图片删除或更改
    如图:
    在这里插入图片描述
    4. 点击确定按钮,整合内容提交给接口
    难点攻克:
    1. 选择一个文件上传,添加第二条时,文件展示有误
    2. 如果我一次增加了多条上传框,但从非第一个的上传按钮上传时,添加到了第一个点击上传的按钮下
    3. 图片的自删和更换
    4. 最后的上传格式
      嗯,从以上几点来一步步来处理问题
      第一步,写出基本上传html:
	  // fileUploadLength 是要添加几条tr的总个数
         <tr v-for="(item,index) in fileUploadLength" :key="index" style="width: 100%;height: 50px;">
            <td>
              <input class="desc">  // 文件描述
            </td>
            <td>
              <input class="ver">  // 文件版本
            </td>
            <td style="width: 100px">
            //上传 - 官网中就有
              <el-upload
                :on-remove="handleRemove" // 文件列表移除文件时的钩子
                :before-upload="beforeUpload" // 上传文件之前的钩子,参数为上传的文件
                :before-remove="beforeRemove"  // 删除文件之前的钩子,参数为上传的文件和文件列表
                :limit="1" // 限制,每个上传按钮只能上传一个文件
                :file-list="fileList[index]" // 文件组
                :multiple="false" 
                :on-exceed="handleExceed" // 文件超出个数限制时的钩子
                class="upload-demo"
                action="">
                <el-button size="mini" type="primary" @click="clickUpload(index)">{{ $t('file.click_upload') }}</el-button>
              </el-upload>
            </td>
            <td>
             // 删除按钮
              <el-button type="text" @click="deleteTr(index)">{{ $t('table.delete') }}</el-button>
            </td>
          </tr>

第二步,充实对应的方法:

1. 只要点击上传就会执行该方法:

// 文件上传之时(文件不会上传成功,在触发下一步操作前截取文件信息)
    beforeUpload(file) {
      if (file) {
      // 添加-跳跃增 => 只能添加到第一位,后面的全删掉
        if (this.index === 0 && this.iNotUpload !== 0 && !this.addUpload) {
          this.fileUploadLength.splice(this.iNotUpload, this.fileUploadLength.length)
        }
        this.fileList[this.index++].push(file)
      }
      return false
    },

现在来说一下,为什么官网直接用的是 fileList,而我的代码用的是 fileList[0]这样的呢?
由于在这个添加会有增加多条tr,而每个tr都有一个上传按钮,如果直接用fileList,当我上传第一个文件之后,
再添加第二条,就会出现第二个文件名也出现在了第一个上传按钮下方的情况。
所以,为了文件和按钮的位置一一对应,使用下标控制。

2. 上传后 return false 相当于上传并没成功,就会自动执行删除操作:

 // 文件列表移除文件时的钩子(就是点击文件后的 x 进行删除或更改的操作)
    handleRemove(file) {
    // 防止 上传没成功就直接删除了文件。
      if (file && file.status === 'success') {  
        for (let i = 0; i < this.fileList.length; i++) {
         // 若是点击要删除的文件名与文件组中的某个文件名相同,则取其下标
          if (this.fileList[i].length && file.name === this.fileList[i][0].name) {
            this.fileList.splice(i, 1)
            this.index = i
            this.fileList.splice(i, 0, []) // 删除该下标对应文件后,给该下标插入空数组占位,保证fileList长度
            this.addUpload = true
          }
        }
      }
    },

3. 删除之前的询问

 // 删除文件之前的钩子-弹出框询问
    beforeRemove(file, fileList) {
      // 处理 before-upload验证不通过后触发了on-remove的解决办法
      if (file && file.status === 'success') {
        return this.$confirm('你确定删除这个文件?')
      }
    },

4. 限制每个上传按钮对应文件的个数

  // 一个上传按钮只能添加一个文件,限制,不能超过一
    handleExceed(files, fileList) {
      this.$message.warning(this.$t('file.select_aPage'))
    },

和组件中的 :limit 共同使用

5. 上传:

// 点击上传按钮,按照下标上传,处理同时有多个上传按钮 但不按顺序上传的问题
    clickUpload(i) {
      // 新增-上传
      if (i !== 0 && !this.addUpload) {
        this.iNotUpload = i
      }
    },

6. tr 的增加:

// tr的添加按钮
    addTr() {
      // 保证添加首条后再点击添加按钮首条添加文件不会消失
      if (this.fileList.length) {
        this.fileList = this.fileList
      } else {
        this.fileList = []
      }
      this.fileUploadLength.push(0)
      for (let i = 0; i < this.fileUploadLength.length; i++) {
        this.fileList.push([])
      }
    },

7. tr 的删除:

    // tr的删除按钮
    deleteTr(index) {
      this.fileList.splice(index, 1)
      this.fileUploadLength.splice(index, 1)
      this.index--
    },

前三个难点在上述代码中已经解决:
难点一 => 下标控制
难点二 => 上传前触发的钩子方法中,跳跃增的处理
难点三 => 第二段代码,用splice(下标,个数,插入[ ])
现在来处理最后一个难点: 走接口上传!
当时在网上找资料的时候,看到组件中的action里必须要写内容,官网中也是:
在这里插入图片描述
所以我在这里是懵的,最后发现写不写都没啥影响,反正用不到里面的地址,最后都是要走接口的。
方法详情参照链接:https://www.jianshu.com/p/e984c3619019
最后整理文件:

      var formdata = new FormData() // 创建一个对象实例
       // 我们后台不识别直接传一个数组过去,分割成对象
      for (let i = 0; i < this.fileList.length; i++) {
        if (this.fileList[i].length) {
          formdata.append('files', this.fileList[i][0])
        }
      }
      // 若是后台能接收到完整的数组(前提是把fileList中的数组拆成对象):
        formdata.append('files', this.fileList)
      // 键值对类型(this.valObj对象是存放一些别的参数的)
      formdata.append('msgupgradeFileGroup', JSON.stringify(this.valObj))

这些功能是需要前后端联调的,最终完成真的特棒。
项目中有添加也有编辑,这里只是整理了添加,编辑的话也都大同小异。希望以后会更进一步!

猜你喜欢

转载自blog.csdn.net/qq_41612675/article/details/86623200