很开心今天中午没有吃饭!
原因是一直没有解决掉一个小问题,于是一直试错,最后看了下源码才有了点头绪,历时四五个小时才解决掉,有点怀疑自己的能力了,所以写下此文,记录一下今天的囧况!
一般情况下遇到问题,自己先是有个思路,然后search answer,如果看到不符合自己思路的直接略过,有点眉目的扫一遍然后试错,大部分情况下自己的思路是对的,所以解决问题也很快,不幸的是有时候自己的思路一开始就是错的,沿着一贯的作法只能是屡试屡败,比如今天遇到的问题就是这样,所以非常怀疑自己的能力了。

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

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

我的思路:

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,于是有了下面的方法。

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了,发现我的思路是错的。

发现beforeAvatarUpload其实是返回一个Promise

仔细看了下掘金上的这篇文章https://juejin.im/post/59e93cd06fb9a0451968b371,发现upload人家内部确实是想要一个promise,你直接给isSize一个boolean值,最后return出去其实是没有任何作用的,这就解释了为何可以弹出错误信息却可以成功上传了,这个是开始的实现方法。

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到人家真正的实现方法,于是看下源码吧,一看才有点儿眉目。

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的实现,这下清楚了一点,就顺水推舟的有了最终的方法,经过多样测试,的确可以。

最终版代码

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,总是可以悬崖勒马,让我们浪子回头,其实还是自己的功力不深啊,以后多注重基础,多挖掘细节,以小见大,修炼内功!

相信有人还会遇到这个问题,希望可以帮助大家,减少不必要的挣扎,记住午饭还是要吃的!

elementUI upload 对图片的宽高做校验的更多相关文章

  1. iOS学习-压缩图片(改变图片的宽高)

    压缩图片,图片的大小与我们期望的宽高不一致时,我们可以将其处理为我们想要的宽高. 传入想要修改的图片,以及新的尺寸 -(UIImage*)imageWithImage:(UIImage*)image ...

  2. vue : 检测用户上传的图片的宽高

    需求: 用户可上传3-6张图片(第 1 2 3 张必须传),上传的图片必须是540 * 330 像素. 第一步,获取上传的图片的宽高. 初始化一个对象数组,宽高均设为0. 如果用户上传的图片没有上限, ...

  3. AntDesign VUE:上传组件图片/视频宽高、文件大小、image/video/pdf文件类型等限制(Promise、Boolean)

    文件大小限制 - Promise checkFileSize(file, rules) { return new Promise((resolve, reject) => { file.size ...

  4. js判断图片加载完成后获取图片实际宽高

    通常,我们会用jq的.width()/.height()方法获取图片的宽度/高度或者用js的.offsetwidth/.offsetheight方法来获取图片的宽度/高度,但这些方法在我们通过样式设置 ...

  5. RT/Metro商店应用如何如何获取图片的宽高

    RT/Metro商店应用如何如何获取图片的宽高 var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms ...

  6. JS获取图片实际宽高及根据图片大小进行自适应

    JS获取图片实际宽高,以及根据图片大小进行自适应  <img src="http://xxx.jpg" id="imgs" onload="ad ...

  7. java读取远程url图片,得到宽高

    链接地址:http://blog.sina.com.cn/s/blog_407a68fc0100nrb6.html import java.io.IOException;import java.awt ...

  8. JS获取图片实际宽高

    JS获取图片实际宽高,以及根据图片大小进行自适应 <img src="http://xxx.jpg" id="imgs" onload="ada ...

  9. 根据图片url地址获取图片的宽高

    /** * 根据img获取图片的宽高 * @param img 图片地址 * @return 图片的对象,对象中图片的真实宽高 */ public BufferedImage getBufferedI ...

随机推荐

  1. 【Henu ACM Round#18 A】 Multiplication Table

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 遍历i从1..n 看看x%i==0以及x/i<=n是否成立. [代码] #include <iostream> u ...

  2. Vijos——T1053 Easy sssp

    https://vijos.org/p/1053 描述 输入数据给出一个有N(2 <= N <= 1,000)个节点,M(M <= 100,000)条边的带权有向图. 要求你写一个程 ...

  3. 把文件保存到 sdcard

    直接上代码: package com.example.test; import java.io.File; import java.io.FileNotFoundException; import j ...

  4. JAVA基础针对自己薄弱环节总结02(循环)

    循环 A:水仙花. classShuiXianHua { public static void main(String[] args) { for(int i=101;i<1000;i++) { ...

  5. idle-实现清屏

    最近在学习python的时候,需要用到ubuntu的python idle.这个工具可以测试python语法.但是呢,在使用的过程中遇到了一个问题.就是随着你的输入,你会发现这个输入会停留在这个界面的 ...

  6. powershell《语音报警系统》

    用powershell实现:“倩女幽魂姥姥”版<语音报警系统> ------[第一章 前言]------ win7,及以上版本中,是自带语音库的,系统自带一套女声中文库,一套女声英文库.用 ...

  7. TCP连接状态详解

    tcp状态: LISTEN:侦听来自远方的TCP端口的连接请求 SYN-SENT:再发送连接请求后等待匹配的连接请求 SYN-RECEIVED:再收到和发送一个连接请求后等待对方对连接请求的确认 ES ...

  8. HTTP -- 请求/响应 结构

    一:一个HTTP请求报文由四个部分组成:请求行.请求头部.空行.请求数据. 1.请求行 1.请求方法:GET POST 2.URL字段 3.HTTP版本字段 2.请求头 1.Accept:浏览器可接受 ...

  9. 使用C库制作DLL

    一.用C编写制作 DLL 如下图所示,是在C++的基础上新建的项目工程: 新建项目的工程文件中有.cpp文件. 由于我们是用C库制作的DLL,显然用C++来编写的是不合适的,我为什么用C库,而不用C+ ...

  10. Elasticsearch中JAVA API的使用

    1.Elasticsearch中Java API的简介 Elasticsearch 的Java API 提供了非常便捷的方法来索引和查询数据等. 通过添加jar包,不需要编写HTTP层的代码就可以开始 ...