问题描述:
最近在修正完成一个html5多图片批量上传功能时候,需要先读取本地的图片然后预览,用到了FileReader的onload方法来读取base64字符串。
问题在于,假如一次性读取多个图片选择多个图片的时候,该方法可以正确执行图片的个数,但是最后读取到的file信息永远是文件列表中最后一个。
问题代码如下:
var _vars={};
for(var i=0;i< oFiles.length;i++){
var oFile=oFiles[i];
_vars["oFile"+i]=oFile;
console.log("外层loop的index:");
console.log(i);
if(!new RegExp("(jpg|jpeg|gif|png)+","gi").test(oFile.type)){
///alert("照片上传:文件类型必须是JPG、JPEG、PNG或GIF!");
continue;
}
var _listitemElement=$(tpl_list_item.render({}));
_vars["element"+i]=_listitemElement;
var _img_preview=_listitemElement.find('[ui="preview"]');
_vars["preview"]=_img_preview;
var _btn_delete=_listitemElement.find('[ui="btn-delete"]');
_vars["btn_delete"]=_btn_delete;
innerTools.getBase4FromImgFile(oFile,function(base64imgData){
console.log("当前的i:");
console.log(i);
console.log(oFile);
_img_preview.attr("src",base64imgData);
_listitemElement.hide();
rootEL.append(_listitemElement);
var _show_del=settings.showDeleteButton(rootEL,_listitemElement,oFile,base64imgData);
if(_show_del==true){
_btn_delete.show();
}
else if(_show_del==false){
_btn_delete.hide();
}
var _res=settings.onFileHanding(rootEL,_listitemElement,oFile,base64imgData);
if(_res==true){
_listitemElement.show();
}
else{
_listitemElement.hide();
}
me.initListElementEvents(_btn_delete,rootEL,_listitemElement,oFile,base64imgData);
});
}
完整代码如下【请注意对比,为什么用interval定时检测执行】:
/**
* 这是html5的图片批量上传组件。
*/
define("ui.img-muti-uploader",function(require,exports,module){
var tpls=require("tpl.common-ui");
var tpl_add_button=laytpl(tpls["img-muti-uploader-add-button"]);
var tpl_list_item=laytpl(tpls["img-muti-uploader-listitem"]);
var appData={};
var rootEL="";
var _file_add="";
var settings={
wrapper:""
,showDeleteButton:function(ListContainer,itemElement,file,srcBase64){
return true;
}//是否显示删除按钮,假如返回的是true,那么显示,否则不显示。
,onFileSelected:function(files){
}//--当选择一个或多个时候触发该方法。
,onFileHanding:function(ListContainer,itemElement,file,srcBase64){
return true;
}//在渲染上传文件单元时候触发该方法,返回true时候就显示,否则不显示。应用场景举例:当选择合适的图片时候,组件就会渲染file item模板,然后将有效图片的base64带前缀赋予图片,当然,最后还会加入到图片列表容器显示出来,
//假如你要做每张图片都上传到服务器然后按照返回的url地址显示的话,没有上传成功就不显示,那么你需要将设置itemElement为display none,然后将srcBase64的数据读取出来,上传服务器,假如成功设置为显示,否则做提示和删除元素。
,onFileItemDelete:function(ListContainer,itemElement,file,srcBase64){
}//点击删除按钮时候的操作。
};
var innerTools={
getBase4FromImgFile:function(file,callBack){
console.log("当前的file:");
console.log(file);
var reader = new FileReader();
reader.onload = function(e) {
var base64Img= e.target.result;
//var $img = $('<img>').attr("src", e.target.result)
//$('#preview').empty().append($img)
if(callBack){
callBack(base64Img);
}
};
reader.readAsDataURL(file);
}
};
var app={
init:function(opts){
var me=this;
settings= $.extend({},settings,opts);
rootEL=$(settings.wrapper);
me.firstRenderView();
}
//--第一次初始化界面。
,firstRenderView:function(){
var _html=tpl_add_button.render({});
rootEL.empty();
var el1=$(_html);
_file_add=el1.find('[ui="add-file"]');
rootEL.append(el1);
this.initAddButtonEvents(_file_add);
}
,initAddButtonEvents:function(fileInputElement){
var me=this;
fileInputElement.change(function(e){
if (e.target.files.length === 0) {
alert("请选择图片");
return; }
var oFiles = e.target.files;
//if (!rFilter.test(oFile.type)) { alert("You must select a valid image file!"); return; }
/* if(oFile.size>5*1024*1024){
message(myCache.par.lang,{cn:"照片上传:文件不能超过5MB!请使用容量更小的照片。",en:"证书上传:文件不能超过100K!"})
changePanel("result");
return;
}*/
//--没办法,里面是异步的,for循环会先循环一次然后执行异步内容,也就是说,所有的变量最后都会变成最后一个。现在采用队列执行的方式来处理。
var _queueBusy=false;
var _queueFinish=false;
var _currentQueueIndex=0;
var _vars={};
var _queueInterval=setInterval(function(){
if(_queueBusy==true){
return;
}
if(_queueFinish==true){
clearInterval(_queueInterval);
return;
}
if(_currentQueueIndex>=oFiles.length){
_queueFinish=true;
return;
}
_queueBusy=true;
var _oFile=oFiles[_currentQueueIndex];
console.log("现在执行队列:"+_currentQueueIndex);
if(!new RegExp("(jpg|jpeg|gif|png)+","gi").test(_oFile.type)){
///alert("照片上传:文件类型必须是JPG、JPEG、PNG或GIF!");
_currentQueueIndex++;
_queueBusy=false;
return;
}
var i=_currentQueueIndex;
_currentQueueIndex++;
_vars["oFile"+i]=oFiles[i];
_vars["element"+i]=$(tpl_list_item.render({}));
_vars["preview"+i]=_vars["element"+i].find('[ui="preview"]');
_vars["btn_delete"+i]=_vars["element"+i].find('[ui="btn-delete"]');
innerTools.getBase4FromImgFile(_vars["oFile"+i],function(base64imgData){
_vars["preview"+i].attr("src",base64imgData);
_vars["element"+i].hide();
rootEL.append(_vars["element"+i]);
var _show_del=settings.showDeleteButton(rootEL,_vars["element"+i],_vars["oFile"+i],base64imgData);
if(_show_del==true){
_vars["btn_delete"+i].show();
}
else if(_show_del==false){
_vars["btn_delete"].hide();
}
var _res=settings.onFileHanding(rootEL,_vars["element"+i],_vars["oFile"+i],base64imgData);
if(_res==true){
_vars["element"+i].show();
}
else{
_vars["element"+i].show();
}
me.initListElementEvents(_vars["btn_delete"+i],rootEL,_vars["element"+i],_vars["oFile"+i],base64imgData);
_queueBusy=false;
});
},20);
return;
var _vars={};
for(var i=0;i< oFiles.length;i++){
var oFile=oFiles[i];
_vars["oFile"+i]=oFile;
console.log("外层loop的index:");
console.log(i);
if(!new RegExp("(jpg|jpeg|gif|png)+","gi").test(oFile.type)){
///alert("照片上传:文件类型必须是JPG、JPEG、PNG或GIF!");
continue;
}
var _listitemElement=$(tpl_list_item.render({}));
_vars["element"+i]=_listitemElement;
var _img_preview=_listitemElement.find('[ui="preview"]');
_vars["preview"]=_img_preview;
var _btn_delete=_listitemElement.find('[ui="btn-delete"]');
_vars["btn_delete"]=_btn_delete;
innerTools.getBase4FromImgFile(oFile,function(base64imgData){
console.log("当前的i:");
console.log(i);
console.log(oFile);
_img_preview.attr("src",base64imgData);
_listitemElement.hide();
rootEL.append(_listitemElement);
var _show_del=settings.showDeleteButton(rootEL,_listitemElement,oFile,base64imgData);
if(_show_del==true){
_btn_delete.show();
}
else if(_show_del==false){
_btn_delete.hide();
}
var _res=settings.onFileHanding(rootEL,_listitemElement,oFile,base64imgData);
if(_res==true){
_listitemElement.show();
}
else{
_listitemElement.hide();
}
me.initListElementEvents(_btn_delete,rootEL,_listitemElement,oFile,base64imgData);
});
}
});
}
//--初始化每个图片单元的相关事件,譬如,删除,
,initListElementEvents:function(btnDelElement,rootEl,itemEl,file,base64ImgData){
btnDelElement.click(function(){
//alert("点击了删除按钮。");
console.log(itemEl);
settings.onFileItemDelete(rootEl,itemEl,file,base64ImgData);
});
}
};
module.exports=app;
});
<li class="up-entry"><input class="upfile" type="file" accept="image/*" multiple="" ui="add-file"></li>
<li class="up-pic up-over" ui="fileitem">
<div class="clip">
<img src="http://1diandi.oss-cn-qingdao.aliyuncs.com/2014-12-18/a6809a02164140ddb644f064e300a733.jpg" ui="preview" style="width: 65px; height: 65px; display: block; margin-top: 0px;"></div>
<div class="up-mask"></div>
<div class="up-progress">
<div class="pos" ui="progress-bar" style="-webkit-transition: all 1s ease-out; transition: all 1s ease-out; width: 38px;"></div>
</div>
<div class="up-fail">上传失败</div>
<div class="up-success">上传失败</div>
<a class="btn-del" href="javascript:void(0)" title="删除图片" ui="btn-delete"><i class="fa fa-times-circle"></i></a>
</li>
注意,这个组件用在整体的前端环境中,需要有对应的模板,seajs的配置等等。
执行界面: