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

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

  • 文件上傳邏輯
    攜帶token上傳文件到文件服務器,上傳成功服務器返回體裏包含fileIdfileName,上傳失敗返回失敗code,
  • 文件下載邏輯
    根據fileId調接口獲取二進制流文件,根據fileName的後綴獲取文件類型,把二進制文件根據文件類型生成文件。
  • 其餘邏輯html

    1. 文件上傳前需判斷上傳文件類型(文件後綴)及文件大小是否超限,簡單不作說明

碰到問題以下

問題 1.文件上傳須要攜帶 token,並放置於 header 裏

解決方案;
使用el-upload提供的header便可ios

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

問題 2.圖片預覽時若是圖片不存在可能會返回二進制的 json 文件流,須要特殊處理

判斷預覽時返回的二進制流,分狀況處理element-ui

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則判斷爲上傳失敗,其餘狀況則標記爲上傳成功。json

而開發過程倒是不處理httpCode而是根據responseBody裏的code字段進行判斷,雖然我也感受經過httpCode更合適,可是碰到不少狀況都是經過響應體裏的code來判斷的(難不成是由於後端同事不知道怎麼處理httpCode?)axios

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" />
相關文章
相關標籤/搜索