利用jquery.form实现异步上传文件
实现原理
目前需要在一个页面实现多个地方调用上传控件上传文件,并且必须是异步上传。思考半天,想到通过创建动态表单包裹上传文件域,利用jquery.form实现异步提交表单,从而达到异步上传的目的,在上传完毕后移除上传表单,避免与原有表单形成嵌套,导致原有的表单无法正常提交。同时该方式还支持一次上传一个文件,重复上传或者一次上传多个文件,具有较好的方便性。
代码实现
ayscUploadFile方法包含两个参数, wrapId和postMap。
wrapId被指定为要被上传表单包裹的位置id。
postMap是一个对象,主要包含以下信息:
1、表单提交地址Url
由于上传文件的表单都是enctype='multipart/form-data',不能使用post提交文本参数,需要使用get方式提交其他参数,因此要传递额外的参数在url中直接带上参数。
2、type参数
允许上传的文件类型
3、folder参数
指定上传文件的自定义存储子目录,默认不需要指定。
4、beforeCallback
beforeCallback为ajax提交表单之前事件触发函数
5、successCallback
successCallback为上传成功后的处理函数
6、errorCallback
errorCallback为ajax异步提交表单失败后的处理函数
函数功能
1、异步上传文件
2、支持批量上传文件
function ayscUploadFile(wrapId, postMap){ /*判断被包裹的id是否存在*/ if(wrapId == "undefined" || wrapId.length == 0){ alert("被包裹的id不存在"); return false; }else{ wrapId = wrapId.indexOf("#") >= 0 ? wrapId : "#"+ wrapId; } if(!(typeof(postMap) == "object")){ alert("上传配置参数错误"); return false; } var url = postMap["url"]; /*判断url是否为空*/ if(!(url != "undeifned" && url.length > 0)){ alert("上传地址错误"); return false; }else{ /*上传文件类型*/ var type = ("type" in postMap) ? postMap["type"] : ""; /*自定义上传文件目录*/ var folder = ("folder" in postMap) ? postMap["folder"] : ""; /*url地址加上限制上传文件的类型*/ if(type.length > 0){ url = adArgsToUrl(url, "type", type); } /*url地址加上自定义的上传文件存储位置*/ if(folder.length > 0){ url = adArgsToUrl(url, "folder", folder); } } /*表单id*/ var formId = "frm_"+ wrapId.replace("#", ""); /*生成表单*/ var formContent = "<form id='"+ formId +"' name='"+ formId +"' action='"+ url+"' method='post' enctype='multipart/form-data'></form>"; /*将表单包裹在指定的id上*/ if($("form[id="+ formId +"]").length == 0){ $(wrapId).wrap(formContent); } /*验证表单中文件域是否已经选择文件*/ var checkForm = true; $("form[id="+ formId +"] > :file").each(function(){ if(this.value.length == 0){ alert("尚未选择文件,请选择文件"); checkForm = false; return; } }); if(checkForm){ /*回调方法*/ var beforeCallback = postMap["beforeCallback"]; var successCallback = postMap["successCallback"]; var errorCallback = postMap["errorCallback"]; /*异步上传文件*/ $("#" + formId).ajaxSubmit({ dataType:"html", beforeSend:function(httpRequest){ if(typeof(beforeCallback) == "function"){ if(!beforeCallback.call(null, formId)){ httpRequest.abort(); alert("终止执行ajax异步提交") } }else{ alert("正在上传文件,请耐心等待,不要关闭浏览器"); } }, success:function(responseText){ alert(responseText) /*重置表单,确保允许继续添加上传文件*/ resetForm(); if(typeof(successCallback) == "function"){ /*解析返回结果*/ successCallback.call(null, parseResultMap(responseText)); }else{ alert("文件上传成功"); } }, error:function(responseText){ resetForm(); if(typeof(errorCallback) == "function"){ /*解析返回结果*/ errorCallback.call(null); }else{ alert("网络通讯异常,上传失败,请重新上传或稍后再试"); } } }); } /*重置表单信息*/ function resetForm(){ /*重置上传表单内容,方便上传新的文件*/ $("#"+ formId).clearForm(); /*移除表单,恢复原样,避免表单嵌套*/ $(wrapId).unwrap("#"+ formId); } /*解析返回结果*/ function parseResultMap(responseText){ var resultMap = {}; var jsonObject = eval("("+ responseText +");"); var fileName = ("fileName" in jsonObject) ? jsonObject["fileName"] : ""; var fileSize = ("fileSize" in jsonObject) ? jsonObject["fileSize"] : ""; var fileUrl = ("fileKey" in jsonObject) ? jsonObject["fileKey"] : ""; var fileExt = ("fileExt" in jsonObject) ? jsonObject["fileExt"] : ""; var message = ("message" in jsonObject) ? jsonObject["message"] : "上传失败"; var uploadState = ("uploadState" in jsonObject) ? jsonObject["uploadState"] : "0"; fileSize = (parseInt(fileSize)/1024).toFixed(2); resultMap["fileName"] = fileName; resultMap["fileSize"] = fileSize; resultMap["fileUrl"] = fileUrl; resultMap["fileExt"] = fileExt; resultMap["message"] = message; resultMap["uploadState"] = uploadState; return resultMap; } }
上述函数使用需要引入的外部脚本文件
<script type="text/javascript" src="js/jquery.js"></script> <script type="text/javascript" src="js/jquery.form.js"></script>
另外特别说明:
beforeSend方法实际上实在$.ajax中,他接收一个XMLHTTPRequest参数,因此若要挂起ajax请求,执行XMLHTTPRequest的abort()即可。
parseResultMap方法为接收服务器返回的数据并进行处理。、
ajaxSubmit方法实现的异步提交实际上还是jquery的$.ajax的进一步封装,方便了大家的使用.
批量上传文件
该方法也支持一次上传多个文件。但必须创建多个文件域控件,到时上传表单包含这些文件域,实现批量上传文件。
<div id="divWrap"> <input type="file" id="fileOne" name="fileOne" value="" /> <input type="file" id="fileTwo" name="fileTwo" value="" /> <input type="file" id="fileThree" name="fileThree"value="" /> <input type="file" id="fileFour" name="fileFour" value="" /> </div>
需要批量上传的文件域必须被包裹在指定的包裹id里(divWrap),包裹id用于指定动态表单的创建位置。上面的html代码,就是一个包含多个文件域的实例,这样就可以一次上传多个文件。
另外一种 方式可以曲线实现批量上传。用户每上传完毕一个文件后,允许用户继续上传文件,回调函数把服务器返回的上传文件信息输出给页面,页面记录下用户所有的上传文件信息。
参考资料
http://api.jquery.com/Ajax_Events/
http://baike.baidu.com/link?url=zsF_hdb0eZGOtzG2-fwLiHSPJDw0NqZ9GqXScpmBoF3Y_UauuT3HlJrt6raotAsVbVg-_TZQ6zdkh-GYZ91Wn_
http://www.w3school.com.cn/xmldom/dom_http.asp
http://www.cnblogs.com/beniao/archive/2008/03/29/1128914.html
https://github.com/malsup/form