乐趣区

关于前端:一文搞懂elementui的文件上传

一文搞懂 element-ui 的文件上传

  • 文件上传逻辑
    携带 token 上传文件到文件服务器,上传胜利服务器返回体里蕴含 fileIdfileName, 上传失败返回失败code,
  • 文件下载逻辑
    依据 fileId 调接口获取二进制流文件,依据 fileName 的后缀获取文件类型, 把二进制文件依据文件类型生成文件。
  • 其余逻辑

    1. 文件上传前需判断上传文件类型 (文件后缀) 及文件大小是否超限,简略不做阐明

碰到问题如下

问题 1. 文件上传须要携带 token,并搁置于 header 里

解决方案;
应用 el-upload 提供的 header 即可

<el-upload :headers="headers" />
data(){
  return {headers:{token:"111"}
  }
}

问题 2. 图片预览时如果图片不存在可能会返回二进制的 json 文件流,须要非凡解决

判断预览时返回的二进制流, 分状况解决

    handlePreview(file) {// console.log('要预览的文件是:', file)

      // 获取服务端返回的文件 id 和文件名

      const fileId = file.response.body.fileId

      const fileName = file.response.body.fileName

      axios.post(
          this.DOWNLOAD_URL,
          {body: { fileId: fileId}
          },
          {
            // 设置 axios 的 headers 和返回数据类型

            headers: this.headers,
            responseType: 'blob'

          }
        )
        .then(res => {
          // 如果文件未找到还是可能会返回二进制格局的 json 信息, 须要进行解决

          // 失常状况下会返回须要的二进制文件

          if (this.handleMessage(res)) {
            // 解决失常状况的二进制文件

            var fileType = this.getFileType(fileName)
            if (fileType === 'image') {this.downImage(res.data, fileName)
            } else {console.info('非图片格式暂无奈预览')
            }
          }
        })
    },
    handleMessage(res) {
      // 未解决过的 response 对象,如果为失常的二进制流文件返回 true, 如果为二进制的 json 文件则返回 false 并展现 json 内容

      if (res.data && res.data.type) {if (res.data.type === 'application/octet-stream') {
          // 失常的二进制流文件

          return true

        } else if (res.data.type === 'application/json') {
          // 异样的二进制的 JSON 文件

          const reader = new FileReader()
          reader.readAsText(res.data, 'utf-8')
          reader.onload = e => {const result = JSON.parse(reader.result)
            const message = '下载资源文件失败' + reader.result

            console.error('下载资源文件失败:', result)
            this.$message({
              message: message,
              type: 'error',
              duration: 5 * 1000

            })
          }
          return false

        }
      } else {
        console.error('函数入参 response 对象应该是一个残缺的对象, 应该蕴含 data.type 属性')
      }
    },
    getFileType(fileName) {
      // 更多文件类型 参考 https://www.cnblogs.com/zhongcj/archive/2008/11/03/1325293.html

      const arr = fileName.split('.')
      const len = arr.length

      let str = ''

      if (len > 1) {const allowedImageType = this.allowedImageType ||['jpg','jpeg','png']
        const allowedVideoType = this.allowedVideoType || ['mp4']
        const fileType = arr[arr.length - 1].toLocaleLowerCase()
        if (allowedImageType.includes(fileType)) {str = 'image'} else if (allowedVideoType.includes(fileType)) {str = 'video'}
      }
      return str

    },
    downImage(blobData, fileName) {const blob = new Blob([blobData], {type: 'image/jpeg'})
      const reader = new FileReader()
      reader.readAsDataURL(blob)
      reader.onload = e => {const url = URL.createObjectURL(blob)
        // 取到 url, 间接在页面展现即可

      }
    },

问题 3.el-upload 组件展现为上传胜利实际上传失败问题

问题产生起因:
element-uiupload 组件是依据 httpCode 来判断的, 如果为 httpCode<200||httpCode>=300 则判断为上传失败,其余状况则标记为上传胜利。

而开发过程却是不解决 httpCode 而是依据 responseBody 里的 code 字段进行判断, 尽管我也感觉通过 httpCode 更适合, 然而碰到很多状况都是通过响应体里的 code 来判断的(难不成是因为后端共事不晓得怎么解决httpCode?)

handleSuccess(res, file, fileList) {
  // 上传胜利函数的 res 是 responseBody 的 body 体
  // 解决 element-ui 认为上传胜利(他是通过 httpCode 为 200 断定为胜利的),实际上传失败状况(通过 responseBody 判断)

  if (res.code && res.code !== 0) {
    // 上传不胜利给出提示信息
    this.$message({
      message: res.message || 'error',
      type: 'error',
      duration: 5 * 1000

    })
    this.$nextTick(function() {
      // 移除上传失败的文件,code 为 0 即为胜利
      const successFileList = fileList.filter(ele => {return ele.response.code + ''==='0'})
      // 从新设置列表为正确的列表
      // this.fileList = successFileList
      // 假上传胜利时也须要进行一次解决
      this.$emit('my-update', successFileList)
    })
  }
},

问题 4. 如何在包装 el-upload 的自定义组件里获取到最新的已上传的文件列表

应用自定义的 v-model 解决在组件最外层获取已上传的文件列表

// 自定义组件内, 设置 v -model

export default {
  model: {
    prop: 'fileList',
    event: 'my-update',
  },
  props: {
    // element-ui 上传组件的文件列表数组

    fileList: {
      type: Array,
      default() {return []
      },
    },
  },
  methods: {
    // 监听 ele-upload 的 change 事件 依据文档仅增加文件、上传胜利和上传失败时都会被调用

    handleChange(file, fileList) {// console.log('文件发生变化', file, fileList)

      this.$emit('my-update', fileList)
    },
    // 删除文件后须要同步触发下事件

    handleRemove(file, fileList) {
      const fileId = file.response.body.fileId

      // console.log('执行删除事件, 要删除的文件 id', fileId, fileList)

      const selectedFileList = fileList.filter(ele => {return fileId !== ele.response.body.fileId})
      // console.log('删除后文件列表:', selectedFileList)

      this.$emit('my-update', selectedFileList)
    },
    // 同时假上传胜利时也须要进行一次解决

  },
}
  <!-- 父组件里应用 -->
  <upload-box  v-model="uploadFileList" />
退出移动版