问题描述:
最近在修正完成一个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的配置等等。
执行界面: