需求
- 批量上傳頭像,且頭像能上傳到對應的人員信息上
- 上傳限制
- 不是立刻上傳
修改默認樣式
因為覺得element組件的el-upload有點復雜,所以這里使用原始的input標簽。不過通常需要換掉原始樣式,只需給input添加一條style="display:none",接着用具有其他樣式的元素包裹它,並在該元素上添加事件(不包裹也行,包裹主要是為了容易看)。
<el-button @click="beforeImagesUpload">批量上傳圖片
<input type="file" style="display:none" id="file" multiple>
</el-button>
點擊觸發該事件相當於點擊了里面的input元素
beforeImagesUpload(){
let file = document.querySelector('#file')//獲取最原始的input元素
file.click()//觸發
}
保存圖片信息
現在要在上面的beforeImagesUpload進行豐富。由於我希望頭像能上傳到對應的人員信息上,那么我至少需要有一個標識幫助我識別這個頭像屬於誰。所以上傳前先要求用戶將圖片命名為對應的id,接着前端通過圖片名稱來獲取對應的標識進行文件上傳。
這里先了解一下圖片文件的數據格式:

如果不想立刻上傳,那么很容易想到的辦法就是先將文件儲存起來:
fileList:[]
async beforeImagesUpload(){
let fileList=[]
let file = document.querySelector('#file')
file.click()
file.onchange = function (event) {
let files = event.target.files
for(let i=0;i<files.length;i++){
let file=files[i]
let filename=file.name//獲取圖片名稱(有后綴)
let id=filename.slice(0,filename.indexOf('.'))//獲取圖片名稱(無后綴)
fileList.push({file:file,id:id,filename:filename})//整合成新的圖片對象,並將其加進圖片列表中
}
}
console.log(fileList)//出錯
}
然而,你會發現控制台打印數據是空的。這是由於同步致使函數直接跳過處理圖片的部分,馬上到了后面的console.log(fileList)
Promise實現異步
這時可以使用promise對象解決。promise對象的函數內有兩個參數:resolve和reject,它們是兩個回調函數,前者表示成功時的回調,后者表示失敗時的回調,這里先不考慮reject的情況:
async beforeImagesUpload(){
let that=this//改變作用域
let promise= new Promise(function (resolve, reject) {
let fileList=[]
let file = document.querySelector('#file')
file.click()
file.onchange = function (event) {
let files = event.target.files
for(let i=0;i<files.length;i++){
let file=files[i]
let filename=file.name
let id=filename.slice(0,filename.indexOf('.'))
fileList.push({file:file,id:id,filename:filename})
}
resolve(fileList)//通過resolve將fileList拋出,在后續使用
}
})
//接着就是處理拋出來的數據了:
//promise接受兩個回調函數作為參數:一個狀態變為Resolved時調用,一個是狀態變為Reject時調用。
//這兩個函數都接受Promise對象傳出的值作為參數。
//第二個函數是可選的,這里先不考慮第二個函數。
promise.then(function(value) {
//狀態為resolved時調用,這里的value就是resolve拋出的數據
console.log(value)//成功打印
that.fileList=value//儲存
});
},
為了更好的處理數據,建議把value傳給另一個函數處理:
promise.then(function(value) {
that.upload(value)//正式上傳 后面寫
}
)
添加限制
假設上傳圖片有兩個前提:
1.最多只能上傳10張
2.圖片大小不能大於300k
這里reject就派上用場的了。現在修改一下promise對象中的內容:
//...
let promise= new Promise(function (resolve, reject) {
//...
file.onchange = function (event) {
let files = event.target.files
//1.判斷圖片數量
if(files.length>10){
reject('page')//如果多於10張,判定為失敗,拋出錯誤'page',停止向下運行。
}else{
for(let i=0;i<files.length;i++){
let file=files[i]
//2.判斷圖片大小
const is300K=file.size>300*1024//判定指標,是否大於300k
if (is300K) {
reject('size')//如果大於300k,判定為失敗,拋出錯誤'size',停止向下運行。
}
let fileName=file.name
let phone=fileName.slice(0,fileName.indexOf('.'))
fileList.push({file:file,phone:phone,fileName:fileName})
}
}
resolve(fileList)//上面均沒有出錯時拋出
}
})
接下來就是處理回調函數:
async beforeImagesUpload(){
//...
let promise= new Promise(function (resolve, reject) {
//...
})
//這里需要promise的第二個回調函數,在狀態為Reject時調用:
promise.then(function(value) {
that.upload(value)//正式上傳
}, function(error) {
//上面設置了兩種錯誤,這里可以用if來判斷錯誤類型,並給出對應的響應
if(error=='page'){
that.$message.error('最多只能上傳10張照片!')
}else if(error=='size'){
that.$message.error('上傳的圖片大小不能超過300K!');
}
});
},
圖片上傳
不是立刻上傳,需要將upload(value)傳過來的值先保存起來,如this.fileList=value,再經過中間函數處理,配合彈框使用。
為了簡便,這里就直接上傳了。批量上傳,說白了其實就是一個一個地上傳,這里我使用的是axios插件:
upload(value){
value.map(item=>{
let fd = new FormData()
fd.append('image',item.file)
fd.append('id',item.id)
axios.post("url",fd,{headers:{'Content-Type': 'multipart/form-data'}})
})
},
