elementUI upload 对图片的宽高做校验

2,457 阅读2分钟

最近在开发项目中用到了element做图片上传,需要对图片进行宽高、大小、格式的判断。upload有对格式的筛选,大小也好校验,难点在于对宽高的判断。

beforeUpload其实是返回一个Promise

<el-upload
      class="upload-demo"
      action="https://jsonplaceholder.typicode.com/posts/"
      :on-preview="handlePreview"
      :on-remove="handleRemove"
      :on-success="handleSuccess"
      :before-upload="beforeUpload"
      accept=".jpg,.png"   
      :file-list="fileList"
      :limit="1"
      list-type="picture"
    >
      <el-button size="small" type="primary">点击上传</el-button>
      <span slot="tip" class="el-upload__tip">(尺寸: 
        <span>{{clientW}}*{{clientH}} </span>
        大小:&lt;35k 格式:jpg png)</span>
    </el-upload>

官方是这么写的

before-upload
上传文件之前的钩子,参数为上传的文件,若返回 false 或者返回 > Promise 且被 reject,则停止上传。

仔细看了下掘金上的这篇文章juejin.cn/post/684490…,发现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);
    })
},
beforeUpload(file) {
    return this.checkWidthHeight(file).then(async () => {
        isSize = true;
    }, () => {
        isSize = false;
    })
}

结果错误信息一闪而过并可以成功上传,没有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的实现,这下清楚了一点,就顺水推舟的有了最终的方法,经过多样测试,的确可以。

最终版代码

    beforeUpload(file) {
      // 限制上传文件的大小
      const isLt = file.size / 1024 / 35 > 1;
      if (isLt) {
        this.$message.error("上传文件大小不得大于35KB");
      }
      //限制图片大小
      let width = this.clientW;
      let height = this.clientH;
      const isSize = new Promise(function(resolve, reject) {
        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('上传文件的尺寸不符合要求!');
          return Promise.reject();
      });
      return !isLt && isSize;
    },

参考:www.cnblogs.com/lewiscutey/…

element还是有很多坑呀,且行且珍惜