项目中遇到的情况是一次性上传多张图片预览,我那时是把图片转base64预览,但问题来了,涉及到异步的东西会有点小坑。 代码基础不会详细讲,想看基础可以移步上一篇我写的h5上传文件-预览篇
举个例子: 我们一次性要上传的图片顺序和大小如下图,
html
<input type="file" multiple="multiple" class="upload_file"/><br/><br/>
<a href="javascript:;" class="upload_btn">上传</a>
<div class="box"></div>
js
var arr_files =[],//发给服务器的图片对象
upload_file = document.querySelector('.upload_file'),//图片上传文本
box= document.querySelector('.box'),//图片显示容器
upload_btn = document.querySelector('.upload_btn');//上传按钮
upload_file.addEventListener('change',function(e){
select.base64(this.files);//base64方式预览
});
//预览图片
function preview(base64_arr){
for(var i=0,b=base64_arr.length;i<b;i++){
var img =document.createElement('img');
img.src=base64_arr[i].base64;
img.style.cssText="width:100px;"
box.appendChild(img);
}
}
重点代码如下
select=(function(){
var way ={
base64:base64,
add:function(key,callback){
this[key]=callback;
}//增加上传预览方法
};
function base64(files){
for(var a=0,f=files.length;a<f;a++){//一次多张图片上传循环遍历
var read = new FileReader();//实例化对象
read.readAsDataURL(files[a]);//读取FileList对象
read.onload=function(e){//读取完成返回base64(this.result)
preview(base64_arr);
}
}
};
return way;
})();
但上面这种方式会有问题的,转base64需要先用FileReader实例化对象再去读取,要等到onload加载完毕才得到base64,但js的事件,定时器,ajax,src地址加载等等都是异步获取,那有可能因为图片的大小不同导致加载的时间有差异,小图会先加载完显示,大图会在最后面显示,并不是我们需要的结果。结果有可能是反过来的!
有想过用计数的方式,这种方式也是node异步经常用的方式,但计数的方式只能知道最后结束了,并不能改变上传的顺序,用promise也不能解决,promise的实例方法then比异步队列先执行的,promise.all方法也还是找不到。 解决的办法是通过闭包缓存for循环的顺序,创建一个数组按照这个顺序添加图片的base64,最后在一次性添加到页面上。
function base64(files){
var base64_arr =[],//存放每一张图的base64图的FileList对象
for(var a=0,f=files.length;a<f;a++){//一次多张图片上传循环遍历
var read = new FileReader();//实例化对象
read.readAsDataURL(files[a]);//读取FileList对象
read.onload=(function(a){//闭包缓存a
return function(e){//读取完成返回base64(this.result)
base64_arr[a]={base64:this.result};//保存每次图片的base64
if(base64_arr.length==files.length-1){//
preview(base64_arr);
}
}
})(a)
}
};
这个是图片上传遇到的一个小坑吧,后面还有还有....,未完待续....!