2018-10-26 Element Ui upload 图片宽高的校验

在调试图片限制宽高时 出现了很多的问题 一开始我直接百度google, 发现都没有这个问题.感觉这应该是很常见的需求, element内部没有实现, 也许是很简单?网上都没有此类问题.
到GitHub的issue里看, 确实有类似的问题, 但没有系统的解决方法.一开始,我的思路就是按照常规的校验方法去校验, 由于js是没有读取图片权限的, 在这里我使用了URL对象的URL.createObjectURL(file)方法, 其中包含一个表示参数中给出的对象的URL, 这个URL的生命周期和创建它的窗口中的document 绑定, 可以用于在浏览器上预览本地图片或者视频.
但是既然是通过url读取宽高就牵扯到图片是否加载完毕的问题, 虽然是在本地创建一个图片对象, 但创建还是有延迟问题.


2018-10-26 Element Ui upload 图片宽高的校验_第1张图片
image.png

打印出来可以看到是有延迟问题的

解决了文件读取问题后我就能拿到图片真实宽高了, 经过反复的debug 我发现img.onload并没有走, isSize也一直是false, 看来这种邯郸学步的方法显然行不通, 想到onload是异步的, 来不及走就return结束了这个方法, 其实最省事的办法, 就是给图片判断加上1秒的延迟, 但这种做法显然是在自掘坟墓.所以还是需要拿到文件真实的加载完成状态, 所以想法异步操作一下, 让onload之后再执行isSize的判断以及return, 于是我就增加回调函数使onload先执行, 然后对isSize有赋值操作.代码如下:


2018-10-26 Element Ui upload 图片宽高的校验_第2张图片
img

之后isSize确实被重新赋值, 也有了正确的提示, 但只是一闪而过, 并成功的上传了???
2018-10-26 Element Ui upload 图片宽高的校验_第3张图片
虽然有错误提示 但还是上传了
2018-10-26 Element Ui upload 图片宽高的校验_第4张图片
反复挠头.jpg

一步步的开始debug了, 发现最后还是可以回到return的, 但是不知道原因, 接着又开始google了, 发现我的思路是错的.我发现beforeAvatarUpload其实是返回一个Promise
我在查看了一篇文章后, 发现Element Ui的upload人家内部确实是想要一个promise, 直接给isSize一个boolean值return出去其实是没有任何作用的, 这就解释了为什么可以弹出错误信息却可以成功上传了, 这个是开始的实现方法
再后来我通过查看源码之后发现this.beforeUpload是一个真正的promise, 也就是说必须返回一个promise, 简单的boolean值是没用的, 因为Element组件内部还有很多的对promise的实现.
这下清楚了一点, 就有了最终的方法, 经过多次测试终于可以了.

beforeAvatarUpload(file) {
        this.filterType = []
        if (this.pType) { // 判断父组件传过来的可上传图片类型
          const typeArr = this.pType
          for (const i in typeArr) {
            this.filterType.push(this.imgType[typeArr[i]])
          }
        } else { // 如果没有直接赋值为默认
          this.filterType = this.imgType
        }
        let typeFlag = false
        for (const o in this.filterType) {
          if (this.filterType[o] === file.type) {
            typeFlag = true
          }
        }
        const isLt1M = file.size / 1024 / 1024 < 1
        if (!typeFlag) {
          this.$message.error('上传图片只能是 ' + this.filterType + ' 格式!')
        }
        if (!isLt1M) {
          this.$message.error('上传图片大小不超过 1MB')
        }
        const _width = 210
        const _height = 100
        const isSize = new Promise(function(resolve, reject) {
          const _url = URL.createObjectURL(file)
          const img = new Image()
          if (1) { // 是否判断宽高
            img.onload = function() {
              const valid = img.width === _width
              valid ? resolve() : reject()
            }
          } else {
            resolve()
          }
          img.src = _url
        }).then(() => {
          return true
        }, () => {
          this.$message.error('上传的尺寸必须是宽:' + _width + 'px 高:' + _height + 'px')
          return Promise.reject()
        })
        return typeFlag && isLt1M && isSize
      }

当然 我这里宽高为固定的宽高, 在实际代码中可以是子组件传过来的, 如果没有传值也可以不限制, 判断那里我还没有写.这个功能看似很简单很简单, 但是其实牵扯到promise异步调用返回值, 由于以前异步基本都用在ajax请求, 并没有在别的地方用过, 所以花些时间学习了一下.

你可能感兴趣的:(2018-10-26 Element Ui upload 图片宽高的校验)