很開心今天中午沒有吃飯!
緣由是一直沒有解決掉一個小問題,因而一直試錯,最後看了下源碼纔有了點頭緒,歷時四五個小時才解決掉,有點懷疑本身的能力了,因此寫下此文,記錄一下今天的囧況!
通常狀況下遇到問題,本身先是有個思路,而後search answer,若是看到不符合本身思路的直接略過,有點眉目的掃一遍而後試錯,大部分狀況下本身的思路是對的,因此解決問題也很快,不幸的是有時候本身的思路一開始就是錯的,沿着一向的做法只能是屢試屢敗,好比今天遇到的問題就是這樣,因此很是懷疑本身的能力了。javascript
一開始我直接百度google,發現都沒有這個問題,這應該是一個很常見的需求啊,element 爲啥沒有實現呢,也許是很簡單吧,網上居然沒有此類問題,我到GitHub的issue裏看,確實有相似的問題,但沒有系統的解決方法,涼涼。vue
// 例子中的size和type檢驗
beforeAvatarUpload(file) {
const isJPG = file.type === 'image/png';
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isJPG) {
this.$message.error('上傳icon只能是 PNG 格式!');
}
if (!isLt2M) {
this.$message.error('上傳icon大小不能超過 2MB!');
}
return isJPG && isLt2M;
},
// 推理出的寬高校驗
beforeAvatarUpload(file) {
const isSize = false;
const isJPG = file.type === 'image/png';
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isJPG) {
this.$message.error('上傳icon只能是 PNG 格式!');
}
if (!isLt2M) {
this.$message.error('上傳icon大小不能超過 2MB!');
}
let img = new Image();
var _URL = window.URL || window.webkitURL;
img.onload=function(){
if(img.width == 96 && img.height == 96) {
isSize = true;
} else {
isSize = false;
}
};
img.src = _URL._URL.createObjectURL(file);
if (!isSize) {
this.$message.error('上傳的圖片尺寸只能是100*100!');
}
return isJPG && isLt2M && isSize;
},
通過反覆的debugger發現img.onload壓根不走,isSize始終是false,看來這種模仿的方法顯然是行不通的,想到onload是異步的,來不及走就return結束了這個方法,因此想法async一下,讓onload以後再執行isSize的判斷以及return,因而有了下面的方法。java
beforeAvatarUpload(file) {
const isSize = false;
const isJPG = file.type === 'image/png';
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isJPG) {
this.$message.error('上傳icon只能是 PNG 格式!');
}
if (!isLt2M) {
this.$message.error('上傳icon大小不能超過 2MB!');
}
let img = new Image();
var _URL = window.URL || window.webkitURL;
img.onload=function(){
if(img.width == 96 && img.height == 96) {
isSize = true;
} else {
isSize = false;
}
};
img.src = _URL._URL.createObjectURL(file);
setTimeout(() => {
if (!isSize) {
this.$message.error('上傳的圖片尺寸只能是100*100!');
}
return isJPG && isLt2M && isSize;
});
}
如今isSize確實被從新賦值了,有了正確的提示,但只是一閃而過,併成功的上傳了,很鬱悶,一步步的開始debugger了,發現最後仍是能夠回到return的,可是不知道啥緣由,接着又開始google了,發現個人思路是錯的。git
仔細看了下掘金上的這篇文章http://www.javashuo.com/article/p-zelwnkca-cy.html,發現upload人家內部確實是想要一個promise,你直接給isSize一個boolean值,最後return出去實際上是沒有任何做用的,這就解釋了爲什麼能夠彈出錯誤信息卻能夠成功上傳了,這個是開始的實現方法。github
checkWidthHeight(file) {
return new Promise((resolve, reject) => {
let width = 100;
let height = 100;
var _URL = window.URL || window.webkitURL;
var img = new Image();
img.onload = function() {
let valid = width === this.width && height === this.height;
valid ? resolve() : reject(this);
}
img.src = _URL.createObjectURL(file);
})
},
handleBeforeUpload(file) {
return this.checkWidthHeight(file).then(async () => {
isSize = true;
}, () => {
isSize = false;
})
}
我想這應該沒問題了吧,該有的都有了,最後仍是利用isSize來肯定是否成功檢驗,發現和上次的狀況同樣,沒有質的改變,錯誤信息仍是一閃而過並能夠成功上傳,這下有點慌了,看來沒弄明白爲啥須要promise而胡亂的改造,終究解決不了問題,沒有get到人家真正的實現方法,因而看下源碼吧,一看纔有點兒眉目。web
// https://github.com/ElemeFE/element/blob/dev/packages/upload/src/upload.vue#L77
upload(rawFile) {
this.$refs.input.value = null;
if (!this.beforeUpload) {
return this.post(rawFile);
}
const before = this.beforeUpload(rawFile);
if (before && before.then) {
before.then(processedFile => {
const fileType = Object.prototype.toString.call(processedFile);
if (fileType === '[object File]' || fileType === '[object Blob]') {
if (fileType === '[object Blob]') {
processedFile = new File([processedFile], rawFile.name, {
type: rawFile.type
});
}
for (const p in rawFile) {
if (rawFile.hasOwnProperty(p)) {
processedFile[p] = rawFile[p];
}
}
this.post(processedFile);
} else {
this.post(rawFile);
}
}, () => {
this.onRemove(null, rawFile);
});
} else if (before !== false) {
this.post(rawFile);
} else {
this.onRemove(null, rawFile);
}
},
這才發現this.beforeUpload是一個真正的promise,你給人家必須返回一個promise,簡單的boolean值是沒用的,由於人家內部還有不少的對promise的實現,這下清楚了一點,就順水推舟的有了最終的方法,通過多樣測試,的確能夠。promise
beforeAvatarUpload(file) {
const isJPG = file.type === 'image/png';
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isJPG) {
this.$message.error('上傳icon只能是 PNG 格式!');
}
if (!isLt2M) {
this.$message.error('上傳icon大小不能超過 2MB!');
}
const isSize = new Promise(function(resolve, reject) {
let width = 100;
let height = 100;
let _URL = window.URL || window.webkitURL;
let img = new Image();
img.onload = function() {
let valid = img.width >= width && img.height >= height;
valid ? resolve() : reject();
}
img.src = _URL.createObjectURL(file);
}).then(() => {
return file;
}, () => {
this.$message.error('上傳的icon必須是等於或大於100*100!');
return Promise.reject();
});
return isJPG && isLt2M && isSize;
}
看了最終版的代碼發現確實也很簡單,咱們每每被固有的思惟帶入歧途,好在有偉大的google,老是能夠回頭是岸,讓咱們浪子回頭,其實仍是本身的功力不深啊,之後多注重基礎,多挖掘細節,以小見大,修煉內功!app