elementUI upload 对图片的宽高做校验

6,594 阅读2分钟

前言

在我使用vue+elementUI开发过程中遇到一个问题:upload 对图片的宽高做校验

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

既然没有找到那就只能自己鼓捣了

思路

想要做图片的宽高校验那就要先获取到图片宽高信息:image.onload

onload 事件在图片加载完成后立即执行。

let image = new Image();
image.onload = function() {
    let width = image.width;
    let height = image.height;
};
image.src = "images/bg.jpg";

获取到信息后那就可以进行比较了 比如我需要一张750*420尺寸的图片

let width = 750;  //图片宽度
let height = 420; //图片高度
let image = new Image();
image.onload = function() {
    let isSize = image.width == width && image.height == height;
    if (!isSize) {
        that.$message.error("上传头像图片尺寸不符合,只能是750*420");
    }
};
image.src = "images/bg.jpg";

现在我想获取到上传的图片信息

beforeAvatarUpload(file) {
    // 上传图片前处理函数
    let width = 750;  //图片宽度
    let height = 420; //图片高度
    let _URL = window.URL || window.webkitURL;
    let image = new Image();
    img.onload = function() {
        let isSize = image.width == width && image.height == height;
        if (!isSize) {
            that.$message.error("上传头像图片尺寸不符合,只能是750*420");
        }
        return isSize;
    };
    img.src = _URL.createObjectURL(file);
}

现在isSize确实被重新赋值了,有了正确的提示,但只是一闪而过,并成功的上传了,很郁闷,一步步的开始debugger了,发现最后还是可以回到return的,但是不知道啥原因,接着又开始google了,发现我的思路是错的。

仔细看了下掘金上的这篇文章JS 应用场景(Promise => 图片上传),发现upload人家内部确实是想要一个promise,你直接给isSize一个boolean值,最后return出去其实是没有任何作用的,这就解释了为何可以弹出错误信息却可以成功上传了,这个是刚才的实现方法。

还是去看下源码吧,一看才有点儿眉目

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/jpeg" ||
        file.type === "image/png" ||
        file.type === "image/gif";
    const isLt2M = file.size / 1024 / 1024 < 2;
    let that = this;
    let isAllow = false;
    if (!isJPG) {
        this.$message.error("上传头像图片只能是 jpg、png、gif 格式!");
    }
    if (!isLt2M) {
        this.$message.error("上传头像图片大小不能超过 2MB!");
    }
    const isSize = new Promise(function(resolve, reject) {
        let width = 750;
        let height = 420;
        let _URL = window.URL || window.webkitURL;
        let image = new Image();
        image.onload = function() {
          let valid = image.width == width && image.height == height;
          valid ? resolve() : reject();
        };
        image.src = _URL.createObjectURL(file);
    }).then(
        () => {
          return file;
        },
        () => {
          this.$message.error("上传头像图片尺寸不符合,只能是750*420!");
          return Promise.reject();
        }
      );
    return isJPG && isLt2M && isSize;
}

看了最终版的代码发现确实也很简单,我们往往被固有的思维带入歧途,其实还是自己的功力不深啊,以后还是要多注重基础,多挖掘细节,以小见大,修炼内功,共勉!