element-ui upload組件的http-request自定義上傳文件
element-ui的upload上傳組件(upload組件文檔地址),默認以提供action上傳地址的方式上傳文件,但如果我們使用七牛或者阿里oss上傳文件的話,upload這種默認上傳文件的方式就行不通了,因為阿里oss等自定義上傳接口,往往都有權限,額外的配置參數等限制,所以我們就需要自定義上傳接口啦,好在upload組件提供了http-request屬性可以讓我們自定義上傳api
開始着手實現自定義上傳吧
使用方法
頁面使用模板部分 upload 組件截圖如下
methods 中自定義上傳方法js代碼截圖如下
其中 ossUpload 為我們傳遞給upload組件的自定義上傳方法,ossUploadApi為真正的上傳文件數據到服務器的api,到這里,就已經可以觸發自定義上傳文件函數啦。
關聯上傳鈎子
這里有一個問題,因為對於upload上傳組件來說,不僅僅有上傳文件,還有上傳文件成功 success 和失敗 error 鈎子,需要我們對上傳成功和上傳失敗做一些處理才行。
在沒有自定義上傳文件前,這些上傳鈎子是和上傳文件請求接口相關聯的。而我們自定義了上傳文件操作,所以現在上面的寫法是不能主動觸發upload組件定義的鈎子的。
那么我們怎么把自定義上傳api和upload組件的這兩個鈎子關聯起來呢,element-ui文檔上介紹提供了 http-request 屬性可以讓我們可以自定義上傳,沒有介紹如何使用,這個時候就要發揮我們碼農看源代碼的能力啦。通過斷點源碼找到調用我們自定義上傳文件方法的地方,如下圖所示
通過截圖上面的文字分析,我們添加如下所示代碼即可,即添加return 語句返回promise 結果 ,(注意,因為ossUploadApi這個接口本身實現的時候返回的就是promise(由自己實現返回promise)),所以添加 return 語句返回即可
同時,通過源碼我們也發現,upload組件內部往我們自定的上傳方法中傳遞了一個options參數,其中包含了對upload上傳文件 success 成功鈎子,error 失敗鈎子,progress 上傳進度鈎子,也就是說,其實我們也可以在自定義上傳里面主動調用這些鈎子以實現相應功能(注意自己調用鈎子時候保證回調參數一致)。
回調數據
打印自定義上傳方法的回調數據(由upload組件內部傳遞給我們的數據,通過上面源碼分析截圖調用 httpRequest 的地方,也可以看到回調數據的)
總結:
一,通過 http-request 屬性可以讓我們自定義上傳 api 方法
二,我們有兩種方案可以將自定義上傳方法和upload內部的文件上傳 success,error 鈎子關聯起來
①,自定義上傳方法並返回promise (推薦)
②,在自定義上傳方法中主動調用upload組件提供的鈎子或者調用自己定義的鈎子
完整代碼如下

<template> <el-upload ref="upload" :action="doUpload" :headers="headers" :http-request="ossUpload" :on-preview="handlePictureCardPreview" :on-remove="handleRemove" :on-success="handleSuccess" :on-error="handleError" :before-upload="beforeUpload" :file-list="fileList" :disabled="disable" > <el-button size="small" :disabled="disable" type="primary" > 上傳文件 </el-button> <div slot="tip" class="el-upload__tip" > 支持jpg、png、pdf、word格式,大小不超過500M。 </div> </el-upload> </template> <script> import { getToken } from '@/utils/auth'; import { ossUploadApi } from '@/api/serviceProvider'; export default { name: 'Upload', model: { prop: 'fileList', event: 'change', }, props: { fileList: { type: Array, required: true, }, disable: { type: Boolean, default: false, }, }, data() { return { // 上傳地址 doUpload: process.env.VUE_APP_BASE_API + (process.env.NODE_ENV === 'production' ? '' : '/api') + process.env.VUE_APP_BASE_CONTENT_URL + '/contract/upload', // doUpload: 'https://jsonplaceholder.typicode.com/posts/', // 下載請求頭 headers: { tgt: getToken(), }, }; }, watch: {}, methods: { // 處理文件點擊預覽操作 handlePictureCardPreview(file) { console.log(file); let downUrl = ''; if (file.hasOwnProperty('url')) { downUrl = file.url; } else { downUrl = file.response.message; } // 賦值 const a = document.createElement('a'); // 創建href屬性 a.href = downUrl; // 點擊下載 a.click(); }, // 上傳前 beforeUpload(file) { const limitSize = 500; const isLt500M = file.size / 1024 / 1024 < limitSize; if (!isLt500M) { this.$message.error(`上傳文件大小不能超過 ${limitSize}MB!`); } return isLt500M; }, // 手動刪除文件鈎子 handleRemove(_file, fileList) { console.log(fileList); this.processFileList(fileList); }, // 上傳成功鈎子 handleSuccess(_res, _file, fileList) { console.log(fileList); this.processFileList(fileList); }, // 上傳失敗的鈎子 handleError(err, _file, fileList) { if (err.code !== 200) { this.$message({ message: err.message || '上傳失敗', type: 'warning', }); } this.processFileList(fileList); }, // 自定義處理filelist processFileList(fileList) { fileList.forEach((item) => { if (!item.url && item.response) { const response = item.response; item.url = response.url; } }); this.triggerChange(fileList); }, triggerChange(fileList) { this.$emit('change', fileList); }, // 自定義上傳oss方法 ossUpload(option) { const file = option.file; return ossUploadApi(file); }, }, }; </script> <style lang="scss" scoped></style>