通用上传组件(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 ]);
}
}
});