elementUI upload 对图片的宽高做校验
很开心今天中午没有吃饭!
原因是一直没有解决掉一个小问题,于是一直试错,最后看了下源码才有了点头绪,历时四五个小时才解决掉,有点怀疑自己的能力了,所以写下此文,记录一下今天的囧况!
一般情况下遇到问题,自己先是有个思路,然后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 对图片的宽高做校验的更多相关文章
- iOS学习-压缩图片(改变图片的宽高)
压缩图片,图片的大小与我们期望的宽高不一致时,我们可以将其处理为我们想要的宽高. 传入想要修改的图片,以及新的尺寸 -(UIImage*)imageWithImage:(UIImage*)image ...
- vue : 检测用户上传的图片的宽高
需求: 用户可上传3-6张图片(第 1 2 3 张必须传),上传的图片必须是540 * 330 像素. 第一步,获取上传的图片的宽高. 初始化一个对象数组,宽高均设为0. 如果用户上传的图片没有上限, ...
- AntDesign VUE:上传组件图片/视频宽高、文件大小、image/video/pdf文件类型等限制(Promise、Boolean)
文件大小限制 - Promise checkFileSize(file, rules) { return new Promise((resolve, reject) => { file.size ...
- js判断图片加载完成后获取图片实际宽高
通常,我们会用jq的.width()/.height()方法获取图片的宽度/高度或者用js的.offsetwidth/.offsetheight方法来获取图片的宽度/高度,但这些方法在我们通过样式设置 ...
- RT/Metro商店应用如何如何获取图片的宽高
RT/Metro商店应用如何如何获取图片的宽高 var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms ...
- JS获取图片实际宽高及根据图片大小进行自适应
JS获取图片实际宽高,以及根据图片大小进行自适应 <img src="http://xxx.jpg" id="imgs" onload="ad ...
- java读取远程url图片,得到宽高
链接地址:http://blog.sina.com.cn/s/blog_407a68fc0100nrb6.html import java.io.IOException;import java.awt ...
- JS获取图片实际宽高
JS获取图片实际宽高,以及根据图片大小进行自适应 <img src="http://xxx.jpg" id="imgs" onload="ada ...
- 根据图片url地址获取图片的宽高
/** * 根据img获取图片的宽高 * @param img 图片地址 * @return 图片的对象,对象中图片的真实宽高 */ public BufferedImage getBufferedI ...
随机推荐
- 紫书 例题 9-14 UVa 1218 (树形dp)
这道题有个初始值设成1e9, 然后这个值是要加很多次的,然后就会溢出变成负数, 然后就一直WA, 找这个bug找了一个小时--以后不能随便这样设那么大, 要考虑会不会加很多次然后溢出. 讲一下思路. ...
- Mybatis使用注解进行增删改查
// 增public interface StudentMapper{ @Insert("insert into student (stud_id, name, email, addr_id ...
- HDU1796 How many integers can you find【容斥定理】
题目链接: http://acm.hdu.edu.cn/showproblem.php? pid=1796 题目大意: 给你一个整数N.和M个整数的集合{A1.A2.-.Am}.集合内元素为非负数(包 ...
- SQL查询表中的用那些索引
方法1. 使用系统表 -- 查询一个表中的索引及索引列 USE AdventureWorks2008 GO SELECT indexname = a.name , tablename = c. n ...
- Day1下午解题报告
预计分数:0+30+30=60 实际分数:0+30+40=70 T1水题(water) 贪心,按长度排序, 对于第一幅牌里面的,在第二个里面,找一个长度小于,高度最接近的牌 进行覆盖. 考场上的我离正 ...
- 基于Linux平台的Lotus Domino 8系统部署五部曲(全视频展示)
基于Linux平台的Lotus Domino 8系统部署五部曲(全视频展示),学习就像看电影 第一部:安装部署 第二部:配置Domino 第三部:Notes8客户端配置 第四部:为Domino系统加装 ...
- 2018 java实训总结(时间戳&&主键)
java实训题目:源管理系统. 答辩的时候被老师怼了以下几个的地方: 1.主键改变了 2.没时间戳却说自己的程序里有先后(这就是老师迂腐了,主键自增可以间接反馈出他加入的早晚,即使主键做出了改变但只是 ...
- springboot整合Beetl、BeetlSql实现ajax分页
Beetl是Bee Template Language的缩写,它绝不是简单的另外一种模板引擎,而是新一代的模板引擎,它功能强大,性能良好,超过当前流行的模板引擎.而且还易学易用. BeetSql是一个 ...
- BZOJ 1604 [Usaco2008 Open]Cow Neighborhoods 奶牛的邻居 Treap
题意:链接 方法: Treap 解析: 前几道资格赛的题水的不行,这道Gold的题就够分量辣. 首先这个曼哈顿距离啥的肯定能做文章,怎么转化是个问题,自己玩了一会没玩出来,就查了查曼哈顿距离的转化,发 ...
- iOS 基于第三方QQ授权登录
基于iOS实现APP的第三方QQ登陆.接入第三方SDK时的一个主要的步骤: 1,找到相关的开放平台.QQ互联平台,http://connect.qq.com/: 2,注冊成功后创建自己的APP.填写一 ...