elementUI upload 对图片的宽高作校验

很开心今天中午没有吃饭!
缘由是一直没有解决掉一个小问题,因而一直试错,最后看了下源码才有了点头绪,历时四五个小时才解决掉,有点怀疑本身的能力了,因此写下此文,记录一下今天的囧况!
通常状况下遇到问题,本身先是有个思路,而后search answer,若是看到不符合本身思路的直接略过,有点眉目的扫一遍而后试错,大部分状况下本身的思路是对的,因此解决问题也很快,不幸的是有时候本身的思路一开始就是错的,沿着一向的做法只能是屡试屡败,好比今天遇到的问题就是这样,因此很是怀疑本身的能力了。javascript

问题:elementUI upload 对图片的宽高作校验

一开始我直接百度google,发现都没有这个问题,这应该是一个很常见的需求啊,element 为啥没有实现呢,也许是很简单吧,网上居然没有此类问题,我到GitHub的issue里看,确实有相似的问题,但没有系统的解决方法,凉凉。vue

个人思路:

1.按照正常的校验方法推理对宽高的校验

// 例子中的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

2.增长回调函数使onload先执行,而后对isSize有赋值操做

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

发现beforeAvatarUpload实际上是返回一个Promise

仔细看了下掘金上的这篇文章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

element UI upload 源码

// 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

相信有人还会遇到这个问题,但愿能够帮助你们,减小没必要要的挣扎,记住午餐仍是要吃的!
相关文章
相关标签/搜索