通用上传组件(ajaxFileUpload)
通用上传组件(单文件上传、HTML5批量文件上传)
适用场景:通用上传组件使用频次最高,大多数时候你需要使用它。
基本功能:可实现文件上传、结果回显。(本组件自身不能浏览曾经上传的图片)。
两次提交:一个表单有三个字段:姓名、年龄、照片,照片单独提交一次,把图片在服务端的存储路径返回,放在hidden控件中,与姓名、年龄再一次提交。
原理:ajaxFileUpload是一个Jquery插件,ajax不具备上传文件的能力,ajaxFileUpload通过使用js动态的创建一个隐藏iframe和上传表单实现了异步上传,并监听iframe的加载事件来接收返回数据。提供了近似于ajax的异步操作体验。
多文件上传:使用multiple属性可实现多文件上传,<input type="file" name="img" multiple="multiple" /> multiple 属性是 HTML5 中的新属性,浏览器要支持HTML5才可以,使用有局限。
相册上传组件(批量文件上传)
ajaxFileUpload只提供客户端,要自己开发服务端。
目的:
1.AjaxFileUpload进行上传,简单的上传,切图,验证大小,验证格式要求,一个jsp页面可以满足多个上传控件。
2.可以删除图片进行重新上上传
前提:
为了使去除图片x的位置能显示正确的位置需添加样式(static工程已经加入样式)
/* 上传 */ .uploadCloseBtn{width: 16px;height: 16px;border: 0px solid #d7d7d7;border-radius:9px;text-align: center; line-height: 15px;position: absolute;left: 91px;top:-6px;background: #ffffff;cursor: pointer;} .uploadImgDiv{position: relative;margin-top: 10px;}
步骤:
1.上传界面需要引用:
<script type="text/javascript" src="${ctxStatic}/ajaxfileupload/ajaxfileupload.js"></script>
<script type="text/javascript" src="${ctxStatic}/fdp/upload.js"></script>
2.注意:
页面的样式可以按照各自页面的样式进行控制,下面实例没有那么死,可以随意变动
3.上传jsp详解(jsp):
jsp页面的属性(jsp详解) | |||
---|---|---|---|
|
|||
行号 | 必填属性 | 目的 | 用法 |
4 |
class=“existSize_aaa” value="已上传图片数量" |
为了上传的时候知道还可以上传多少张图片,删除的动态控制 |
一个上传控件一个 input
|
5 |
上传控件需要添加这几个属性,id,name,type,thumbnail,tokenPath,suffix,allowType,fileSize,class, imageCount , multiple 在上传控件的位置
|
上传控件 | 一个上传控件一个 input |
6 | class=“result_aaa” |
服务器响应失败时给的错误提示 |
一个上传控件一个 div |
7 |
class="uploadImgDiv" id="img_aaa_bbb" style="${not empty memberUser.headPicPath?'':'display:none;'}"--》判断当前图片有没有地址,如果没有隐藏起来 |
如果一个控件上传多张图片需要 7-14行进行复制多个, 改变bbb的值 |
|
8 |
class="imgPath" name="headPicPath" --》表单的name属性 value="${memberUser.headPicPath}"--》图片地址 |
隐藏域为了存放上传图片的存储地址 | |
9 |
class="result" |
服务器响应成功时的给的提示 |
如果一个控件上传多张图片需要 7-14行进行复制多个,改变bbb的值 |
10 |
class="preview" src="${ctxfs}${memberUser.headPicPath}@!100x100"--》图片地址 style="${not empty memberUser.headPicPath?'':'display:none;'}"--》 判断当前图片有没有地址,如果没有隐藏起来 |
img标签显示图片 |
如果一个控件上传多张图片需要 7-14行进行复制多个,改变bbb的值 |
11 |
class="uploadCloseBtn” |
删除的图片div 如果删除按钮的x样式位置不对写这个样式进行调节style="left: 70px;top:14px;" |
如果一个控件上传多张图片需要 7-14行进行复制多个,改变bbb的值 |
<div class="form-group"> <label class="control-label col-sm-2" for="inputSuccess"> 会员头像 :</label> <div class="col-sm-5"> <input type="hidden" class="existSize_headPicPath" value="${not empty memberUser.headPicPath?'1':'0'}"/> <input id="fileUpload_headPicPath" name="fileUpload" type="file" thumbnail="100x100" tokenPath="${ctxa}/sys/sysToken/getToken.do" suffix="headPicPath" allowType="jpg,jpeg,png,bmp" fileSize="5242880" class="fileUploadClass"/> <div class="result_headPicPath"></div> <div class="uploadImgDiv" id="img_headPicPath_0" style="${not empty memberUser.headPicPath?'':'display:none;'}"> <input type="hidden" class="imgPath" name="headPicPath" value="${memberUser.headPicPath}"/> <div class="result"></div> <img class="preview" src="${ctxfs}${memberUser.headPicPath}@!100x100" style="${not empty memberUser.headPicPath?'':'display:none;'}"/> <div class="uploadCloseBtn"> <img alt="" src="${ctxStatic}/images/close.gif"/> </div> </div> </div> <div class="col-sm-5"> <p class="help-block">会员头像尺寸要求宽度为120像素、高度为120像素,比例为1:1的图片;支持格式jpg,png。<p> </div> </div>
//文件异步上传 $(function(){ //初始化、验证、取token function init() { var suffix = $(this).attr("suffix"); //获取id上传的后缀名 if(suffix==null || suffix=='' || suffix==undefined){ fdp.msg('缺少参数:后缀'); return false; } var allowType = $(this).attr("allowType"); //获取上传文件的扩展名 if(allowType==null || allowType=='' || allowType==undefined){ fdp.msg('缺少参数:扩展名'); return false; } var fileSize = $(this).attr("fileSize"); //获取上传的文件上传大小 if(fileSize==null || fileSize=='' || fileSize==undefined){ fdp.msg('缺少参数:文件大小'); return false; } var tokenPath = $(this).attr("tokenPath"); //获取token的地址 if(tokenPath==null || tokenPath=='' || tokenPath==undefined){ fdp.msg('缺少参数:获取token地址'); return false; } var thumbnail = $(this).attr("thumbnail"); //截取图片大小 if(thumbnail==null || thumbnail=='' || thumbnail==undefined){ fdp.msg('缺少参数:截图尺寸'); return false; } var existSizeSuffix = $(".existSize_"+suffix).val(); //已上传图片数量 if(existSizeSuffix==null || existSizeSuffix=='' || existSizeSuffix==undefined){ fdp.msg('缺少参数:已上传图片数量'); return false; } var imageCount = $(this).attr("imageCount"); //允许图片数量(上传数量默认为1) if(imageCount==null || imageCount=='' || imageCount==undefined){ imageCount = 1; } var token=null; $.ajax({ //ajax获取token type: 'post', url: tokenPath, dataType: 'json', success: function(data){ token=data.token; ajaxFileUpload(suffix,allowType,fileSize,thumbnail,existSizeSuffix,imageCount,token); }, error: function(data){ return false; } }); } //给file控件挂上传事件 $('.fileUploadClass').change(init); //清理input type="file" 的值 function clearFile(suffix){ /*var file = $('#fileUpload_'+suffix) file.after(file.clone().val("")); file.remove(); */ } function ajaxFileUpload (suffix,allowType,fileSize,thumbnail,existSizeSuffix,imageCount,token){ $.ajaxFileUpload({ url : ctxu + "/common/ajaxfileupload.htm?token="+token, // 默认为post请求 secureuri : false, // 是否启用安全提交,默认为false fileElementId:'fileUpload_' + suffix , //文件选择框的id属性 method:'POST', //文件post提交 data:{format:'json','__fileUpload':'1'}, //告诉服务器请给我返回json格式的数据,spring mvc内容协商支持本参数 dataType:'json', //本组件按什么格式接收服务器返回的数据,可以是json或xml等,空表示直接返回data fileSize:fileSize, //文件大小限制,可选,0 为无限制(IE浏览器不兼容) allowType:allowType, //可选,限定上传文件的格式 success : function(data) { if(data[0].errMsg){ $('.result_' + suffix).html(data[0].errMsg); }else if(data[0].errorToken!=null || data[0].errorToken!=null || data[0].errorToken!=undefined){ $('.result_' + suffix).html(data[0].errorToken); }else{ for(var i = 0;i < data.length;i++){ if(data[i].fileStorageName !=null && data[i].fileStorageName !="" && data[i].fileStorageName !=undefined){ for(var j = 0;j < imageCount;j++){ var size = $('.existSize_' + suffix).val();//取已上传图片数量 size = parseInt(size); if(size >= imageCount){ clearFile(suffix); fdp.msg("最多只能上传"+imageCount+"张"); return; } var imgpath = $('#img_'+ suffix +'_'+ + j).find(".imgPath").val(); if(imgpath==null || imgpath=='' || imgpath==undefined){ $('#img_'+ suffix +'_'+ + j).find(".result").html(data[i].errorMsg);//文件上传后的提示语 $('#img_'+ suffix +'_'+ + j).find(".preview").attr("src",ctxfs+data[i].fileStorageName+"@!"+thumbnail);//给img标签赋图片地址 $('#img_'+ suffix +'_'+ + j).find(".imgPath").val(data[i].fileStorageName);//给图片地址隐藏域赋值 $('#img_'+ suffix +'_'+ + j).find(".preview").css("display",""); $('#img_'+ suffix +'_'+ + j).css("display",""); $('.existSize_' + suffix).val(1 + size);//改变已上传图片数量 break; } } }else{ $('#img_'+ suffix +'_'+ + j).find(".preview").css("display",""); $('#img_'+ suffix +'_'+ + j).find(".result").html(data[i].errorMsg);//上传图片的错误提示 } } } clearFile(suffix); }, complete:function(){ //给file控件再次挂上传事件 $('.fileUploadClass').change(init); }, error : function(data) { // 服务器响应失败时的处理函数 $('.result_' + suffix).html('上传失败,请重试!!'); } }); } //移除图片 $(".uploadCloseBtn").click(function(){ var attrId = $(this).parent().attr('id'); var attrIds = attrId.split("_"); $(this).parent().find(".imgPath").val("");//清除图片地址隐藏域 var existSize = $('.existSize_' + attrIds[1]).val(); var size = parseInt(existSize); $('.existSize_' + attrIds[1]).val(size-1);//改变已上传图片数量 $(this).parent().find(".preview").attr("src",""); $(this).parent().find(".result").html(""); $(this).parent().css("display","none"); }); });
上传代码(ajaxfileupload.js):
/* * ajaxFileUpload.js 无刷新上传图片 jquery 插件,支持 ie6-ie10 * 依赖:jquery-1.6.1.min.js * 主方法:ajaxFileUpload 接受 json 对象参数 * 参数说明: * fileElementId:必选,上传文件域ID * url:必选,发送请求的URL字符串 * allowType:可选,限定上传文件的格式(.jpg,.bmp,.gif,.png) * fileSize:可选,0 为无限制(IE浏览器不兼容) * dataType:本组件按什么格式接收服务器返回的数据,可以是json或xml等,空表示直接返回data * data:可选,将和文件域一同post的参数(json对象) ,data:{format:'json'},告诉服务器请给我返回json格式的数据 * 其它:$.ajax 的参数均为可选参数 * 注:如遇到'无法访问'的脚本错误提示则需要在响应流中加一段脚块一同输出:<script ...>document.domain = 'xxx.com';</script> */ jQuery.extend({ //创建 iframe 元素,接受提交及响应 createUploadIframe : function(id, uri) { //create frame var frameId = 'jUploadFrame' + id; if (window.ActiveXObject) { //fix ie9 and ie 10------------- if (jQuery.browser.version == "9.0" || jQuery.browser.version == "10.0") { var io = document.createElement('iframe'); io.id = frameId; io.name = frameId; } else if (jQuery.browser.version == "6.0" || jQuery.browser.version == "7.0" || jQuery.browser.version == "8.0") { var io = document.createElement('<iframe id="' + frameId + '" name="' + frameId + '" />'); if (typeof uri == 'boolean') { io.src = 'javascript:false'; } else if (typeof uri == 'string') { io.src = uri; } } } else { var io = document.createElement('iframe'); io.id = frameId; io.name = frameId; } io.style.position = 'absolute'; io.style.top = '-1000px'; io.style.left = '-1000px'; document.body.appendChild(io); return io; }, //创建 from 元素,用于提交的表单 createUploadForm : function(id, fileElementId, postData) { //create form<span style="white-space:pre"> </span> var formId = 'jUploadForm' + id; var fileId = 'jUploadFile' + id; var form = $('<form action="" method="POST" name="' + formId + '" id="' + formId + '" enctype="multipart/form-data"></form>'); var oldElement = $('#' + fileElementId); var newElement = $(oldElement).clone(); $(oldElement).attr('id', fileId); $(oldElement).before(newElement); $(oldElement).appendTo(form); //添加自定义参数 if (postData) { //递归遍历JSON所有键值 function recurJson(json) { for ( var i in json) { //alert(i+"="+json[i]) $("<input name='" + i + "' id='" + i + "' value='" + json[i] + "' />").appendTo(form); if (typeof json[i] == "object") { recurJson(json[i]); } } } recurJson(postData); } //set attributes $(form).css('position', 'absolute'); $(form).css('top', '-1200px'); $(form).css('left', '-1200px'); $(form).appendTo('body'); return form; }, //上传文件 //s 参数:json对象 ajaxFileUpload : function(s) { s = jQuery.extend({ allowType : "", fileSize : 0 }, jQuery.ajaxSettings, s); //文件筛选 var fielName = $('#' + s.fileElementId).val(); var extention = fielName.substring(fielName.lastIndexOf(".") + 1).toLowerCase(); if (s.allowType && s.allowType.indexOf(extention) < 0) { // layer.msg("仅支持 (" + s.allowType + ") 为后缀名的文件!", { // icon : 2 // }); layer.msg("仅支持 (" + s.allowType + ") 为后缀名的文件!"); $(".loading").css("display","none"); return; } //文件大小限制 if (s.fileSize > 0) { var fs = 0; try { if (window.ActiveXObject) { //IE浏览器 var image = new Image(); image.dynsrc = fielName; fs = image.fileSize; } else { fs = $('#' + s.fileElementId)[0].files[0].size; } } catch (e) { } if (fs > s.fileSize) { layer.msg("当前文件大小 (" + (fs/1024/1024).toFixed(2) + "M) 超过允许的限制值 (" + (s.fileSize/1024/1024).toFixed(2) + "M)!"); //layer.msg("当前文件大小 (" + fs/1024000 + "M) 超过允许的限制值 (" + s.fileSize/1024000 +"M)!", {icon: 2}); $(".loading").css("display","none"); return; } } var id = new Date().getTime(); //创建 form 表单元素 var form = jQuery.createUploadForm(id, s.fileElementId, s.data); //创建 iframe 贞元素 var io = jQuery.createUploadIframe(id, s.secureuri); var frameId = 'jUploadFrame' + id; var formId = 'jUploadForm' + id; //监测是否有新的请求 if (s.global && !jQuery.active++) { jQuery.event.trigger("ajaxStart"); //触发 AJAX 请求开始时执行函数。Ajax 事件。 } var requestDone = false; //创建请求对象 var xml = {}; if (s.global) jQuery.event.trigger("ajaxSend", [ xml, s ]); //触发 AJAX 请求发送前事件 //上载完成的回调函数 var uploadCallback = function(isTimeout) { var io = document.getElementById(frameId); try { //存在跨域脚本访问问题,如遇到'无法访问'提示则需要在响应流中加一段脚块:<script ...>document.domain = 'xxx.com';</script> if (io.contentWindow) { //兼容各个浏览器,可取得子窗口的 window 对象 xml.responseText = io.contentWindow.document.body ? io.contentWindow.document.body.innerHTML : null; xml.responseXML = io.contentWindow.document.XMLDocument ? io.contentWindow.document.XMLDocument : io.contentWindow.document; } else if (io.contentDocument) { //contentDocument Firefox 支持,> ie8 的ie支持。可取得子窗口的 document 对象。 xml.responseText = io.contentDocument.document.body ? io.contentDocument.document.body.innerHTML : null; xml.responseXML = io.contentDocument.document.XMLDocument ? io.contentDocument.document.XMLDocument : io.contentDocument.document; } } catch (e) { jQuery.handleErrorExt(s, xml, null, e); } if (xml || isTimeout == "timeout") { requestDone = true; var status; try { status = isTimeout != "timeout" ? "success" : "error"; // Make sure that the request was successful or notmodified if (status != "error") { //处理数据(运行XML通过httpData不管回调) var data = jQuery.uploadHttpData(xml, s.dataType); // If a local callback was specified, fire it and pass it the data if (s.success){ try{ //调用成功回调函数 s.success(data, status); }catch(e){ //本组件用户写的成功回调函数发生了异常 alert("开发者你好,你编写的success函数生成异常,请你自行修复。"+e); } } // Fire the global callback if (s.global) jQuery.event.trigger("ajaxSuccess", [ xml, s ]); } else jQuery.handleErrorExt(s, xml, status); } catch (e) { status = "error"; jQuery.handleErrorExt(s, xml, status, e); } // The request was completed if (s.global) jQuery.event.trigger("ajaxComplete", [ xml, s ]); // Handle the global AJAX counter if (s.global && !--jQuery.active) jQuery.event.trigger("ajaxStop"); // Process result if (s.complete) s.complete(xml, status); jQuery(io).unbind(); setTimeout(function() { try { $(io).remove(); $(form).remove(); } catch (e) { jQuery.handleErrorExt(s, xml, null, e); } }, 100); xml = null; } }; //超时检查,s.timeout 毫秒后调用 uploadCallback 回调函数提示请求超时 if (s.timeout > 0) { setTimeout(function() { // Check to see if the request is still happening if (!requestDone) uploadCallback("timeout"); }, s.timeout); } try { //设置动态 form 表单的提交参数 // var io = $('#' + frameId); var form = $('#' + formId); $(form).attr('action', s.url); $(form).attr('method', 'POST'); $(form).attr('target', frameId); if (form.encoding) { form.encoding = 'multipart/form-data'; } else { form.enctype = 'multipart/form-data'; } $(form).submit(); } catch (e) { jQuery.handleErrorExt(s, xml, null, e); } //向动态表单的页面加载事件中注册回调函数 if (window.attachEvent) { document.getElementById(frameId).attachEvent('onload', uploadCallback); } else { document.getElementById(frameId).addEventListener('load', uploadCallback, false); } return { abort : function() { } }; }, //上传文件 uploadHttpData : function(r, type) { //alert("type=" + type + ";uploadHttpData" + JSON.stringify(r)) var data = !type; data = type == "xml" || data ? r.responseXML : r.responseText; // If the type is "script", eval it in global context if (type == "script") { jQuery.globalEval(data); } // Get the JavaScript object, if JSON is used. if (type == "json") { //alert(data + " " + jQuery.type(data)); if (jQuery.type(data) === "string") { var b1 = data.indexOf(">") != -1; var b2 = data.indexOf("<") != -1; var b3 = data.toLowerCase().indexOf("pre") != -1; if (b1 && b2 && b3) { data = jQuery.parseJSON(jQuery(data).text());//去掉<pre>标签,转成json对象 } else { data = jQuery.parseJSON(data);//转成json对象 } } //eval("data = " + data);//原始代码 } // evaluate scripts within html if (type == "html") { jQuery("<div>").html(data).evalScripts(); } return data; }, handleErrorExt : function(s, xhr, status, e) { // If a local callback was specified, fire it if (s.error) { s.error.call(s.context || s, xhr, status, e); } // Fire the global callback if (s.global) { (s.context ? jQuery(s.context) : jQuery.event).trigger("ajaxError", [ xhr, s, e ]); } } });