这里用的是一个隐藏的iframe,这样可以让form表单提交到这个iframe里面,用户就看不到页面的刷新了
前段时间在解决ajax上传文件时折腾了好一阵。直接用$.post上传文本信息肯定是没有问题的。但是$.post直接上传图片是不可行的。
后来看到网上的一些解决方案,有现成的ajax上传文件的封装的方法也有利用flash的。flash确实是个好方法 但是不是每个人都会flash的而且下载下来现成的方法要做修改也不是件易事,且文件相对较大。
最后只好模拟iframe来实现。发现相当的简单。
<iframe name="ajaxUpload" style="display:none"></iframe>
<form name="from1" id="from1" method="post" action="url" enctype="multipart/form-data" target="ajaxUpload"> 这里是重点。要上传文件enctype这个属性不可少,target的值改为iframe的name的值。
<table>
<tr>
<td>附件:</td>
<td><input type="file" id="document" name="document"/></td>
</tr>
</table>
</form>
上面是HTML
下面写一下js代码,我是用的jQuery所以在用的时候载入jquery的库是必不可少的。
$(function(){
if($.browser.msie){
window.form1.submit();}else{
$("#form1").submit();}
});
//这里是做了一个浏览器版本的判断,因为IE是不太符合规范的一个浏览器,尤其是IE6。IE6是不直接支持$("#idName").submit();这种方式的。
然后在服务端要怎么着呢,而且还得返回一个值,直接submit是无法返回值的
public void Upload()
{
HttpPostedBase ff=Request.Files["document"];//这里是获取上传的文件流,也可以用索引值来表示如果是多个文件的话
string fileName=System.DateTime.Now+ff.FileName.ToString(); //这里取出来的文件名是没有后缀的,所以要保存的话还需要取出文件拓展名。这里就不写过细,只是为描述这样一个思路。
try{
SaveAs(documentPath+fileName+extendtionName);
Response.Write("<script type='text/javascript' type='language'>parent.window.callBackMethod('上传成功');</scrpt>");
}
catch
{
Response.Write("<script type='text/javascript' type='language'>parent.window.callBackMethod('上传失败');</scrpt>"); //parent.window.methodName();这个是JS调用父页的方法。因为现在模拟一个iframe上传文件,这个iframe的作用就是一个中间站的作用。在父页点击上传后通过target会将页面文档流传入iframe中再上传服务端作处理。服务端有响应之后然后再在iframe里面显示出来,而不是直接在父页面显示出结果。这里可能就是一个alert()弹出一个对话框提示一下,如果是这样那么不调父页方法也行。如果想把这提示的内容丰富一点比如弹出个类似人人网的蓝色的对话框之类的。
}
}
模拟iframe其实是页面局部更新,但是页面中的这个iframe没有内容而且还是不显示的,所以它刷新了完全不会影响到整个页面。
--------------------------------------------------------------------------------------------------------------------------------------------------------------
最近看了一些jQuery即时上传的插件,总算看懂了些门路。现将其最为核心的一部分抽取出来,以期用最简单的例子来说明jQuery图片即时上传的原理。
首先本用例一共包含3个文件:
1、上传面板HTML文件。
2、上传处理PHP文件。
3、jQuery库。
第一、上传面板HTML文件(index.html)。
其主要包含了jQuery库、即时上传所需js、表单和iframe框架。下面是其源码,其中已附详细注释。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>jQuery Upload Image</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Language" content="zh-CN" /> <!--<script type="text/javascript" src="jquery-1.6.2.min.js"></script>--> <!-- 本地jquery库--> <script type="text/javascript" src="http://files.cnblogs.com/Zjmainstay/jquery-1.6.2.min.js"></script> </head> <body> <style> #exec_target{display:none;width:0;height:0;} #feedback{width:1200px;margin:0 auto;} #feedback img{float:left;width:300px;height:300px;} </style> <script type="text/javascript"> $(document).ready(function(){ //选择文件成功则提交表单 $("#upload_file").change(function(){ if($("#upload_file").val() != '') $("#submit_form").submit(); }); //iframe加载响应,初始页面时也有一次,此时data为null。 $("#exec_target").load(function(){ var data = $(window.frames['exec_target'].document.body).find("textarea").html(); //若iframe携带返回数据,则显示在feedback中 if(data != null){ $("#feedback").append(data.replace(/</g,'<').replace(/>/g,'>')); $("#upload_file").val(''); } }); }); </script> <form id="submit_form" method="post" action="submit_form_process.php" target="exec_target" enctype="multipart/form-data"> <input type="file" name="upload_file" id="upload_file"> <!-- 添加上传文件 --> </form> <iframe id="exec_target" name="exec_target"></iframe> <!-- 提交表单处理iframe框架 --> <div id="feedback"></div> <!-- 响应返回数据容器 --> </body> </html>
第二、上传处理PHP文件(submit_form_process.php)。
其主要包含了图片文件的简单上传,及返回图片标签<img>,其中存储刚上传的图片。下面是其源码。
<?php //header('content-type:text/html charset:utf-8'); /* 这句要删除,否则可能会导致IE下回传HTML变成下载 */ //不存在当前上传文件则上传 if(!file_exists($_FILES['upload_file']['name'])) move_uploaded_file($_FILES['upload_file']['tmp_name'],iconv('utf-8','gb2312',$_FILES['upload_file']['name'])); //输出图片文件<img>标签 echo "<textarea><img src='{$_FILES['upload_file']['name']}'/></textarea>"; //End_php
总结之原理透析:
讲到jQuery即时上传,不知道其原理的人第一想法一般都是使用AJAX(补注:当时不知道有FormData对象),我也尝试过。但是,由于上传文件不同于一般数据的POST,它需要表单form的提交来完成。因此,jQuery上传插件也是将<input type="file">的数据转至一个新生的form当中将其提交,而表单的target指向新生的iframe,在iframe中做表单提交后的处理,完成后iframe会重新加载并包含处理结果,通过iframe的load事件便可捕捉并获取处理结果,回传至原表单所在的页面(feedback)中,实现jQuery即时上传的效果。而在表单提交的时候,为了实现选择文件后即时提交表单,则使用了input标签的change事件(index.html L19-21),只要选择了文件,input的值就会发生变化,此时就可以提交表单进行处理了。
软件包下载:最简单的jQuery即时上传示例
/*************************************** 追加 ***************************************/
受@东方翔 评论提示,测试了一下$.ajax 的FormData对象,然后发现成功了(FF、Chrome测试成功),嘿嘿~下面是源码,控制文件为submit_form_process.php不变。
特别的:contentType: false,
processData: false,
这两个参数是必须的。
缺少contentType: false,$_FILES值为空。
缺少processData: false,FF控制台报错:“NS_ERROR_XPC_BAD_OP_ON_WN_PROTO: Illegal operation on WrappedNative prototype object”,直接不能运行。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>FormData</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Language" content="zh-CN" /> <script type="text/javascript" src="http://files.cnblogs.com/Zjmainstay/jquery-1.6.2.min.js"></script> </head> <body> <style> #feedback{width:1200px;margin:0 auto;} #feedback img{float:left;width:300px;height:300px;} </style> <div> <!-- 点击图片添加文件方式 --> <img src="http://f7-preview.awardspace.com/zjmainstay.co.cc/jQueryExample/jquery_upload_image/files/addfile.jpg" onclick="getElementById('inputfile').click()" title="点击添加图片" alt="点击添加图片"> <input type="file" name="image" style="opacity:0;filter:alpha(opacity=0);" id="inputfile"/> </div> <div id="feedback"></div> <!-- 响应返回数据容器 --> <script type="text/javascript"> $(document).ready(function(){ $("#inputfile").change(function(){ //创建FormData对象 var data = new FormData(); //为FormData对象添加数据 // $.each($('#inputfile')[0].files, function(i, file) { data.append('upload_file', file); }); $.ajax({ url:'submit_form_process.php', type:'POST', data:data, cache: false, contentType: false, //不可缺 processData: false, //不可缺 success:function(data){ data = $(data).html(); if($("#feedback").children('img').length == 0) $("#feedback").append(data.replace(/</g,'<').replace(/>/g,'>')); else $("#feedback").children('img').eq(0).before(data.replace(/</g,'<').replace(/>/g,'>')); } }); }); }); </script> </body> </html>
/*************************************** 追加2 ***************************************/
多图上传实现(独立于上面两个版本的文件):
1、index.html文件
功能:点击图片添加文件、添加多个文件、即时上传文件、显示上传文件反馈信息。
包含技术:
1)$.ajax
2)$.ajax 发送FormData对象
3)input multiple="multiple"上传多个文件
4)img onclick="getElementById('inputfile').click()" 点击图片实现添加文件操作
5)input type="file" 样式:height:0;0;z-index: -1;隐藏添加文件按钮(Chrome下使用display:none会导致点击失效)
源码:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Easy Ajax FormData Upload Multiple Images</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Language" content="zh-CN" /> <script type="text/javascript" src="http://files.cnblogs.com/Zjmainstay/jquery-1.6.2.min.js"></script> </head> <body> <style> #feedback{width:1200px;margin:0 auto;} #feedback img{float:left;width:300px;height:300px;} #ZjmainstaySignaturePicture,#addpicContainer{float:left;width: 100%;} #addpicContainer{margin-left:5px;} #ZjmainstaySignaturePicture img{width: 535px;} #addpicContainer img{float: left;} .loading{display:none;background:url("http://f7-preview.awardspace.com/zjmainstay.co.cc/jQueryExample/jquery_upload_image/files/ui-anim_basic_16x16.gif") no-repeat scroll 0 0 transparent;float: left;padding:8px;margin:18px 0 0 18px;} </style> <div id="ZjmainstaySignaturePicture"><a href="http://www.cnblogs.com/Zjmainstay"><img src="http://pic002.cnblogs.com/images/2012/383557/2012071311244097.jpg"/></a></div> <div id="addpicContainer"> <!-- 利用multiple="multiple"属性实现添加多图功能 --> <!-- position: absolute;left: 10px;top: 5px;只针对本用例将input隐至图片底下。--> <!-- height:0;0;z-index: -1;是为了隐藏input,因为Chrome下不能使用display:none,否则无法添加文件 --> <!-- onclick="getElementById('inputfile').click()" 点击图片时则点击添加文件按钮 --> <img onclick="getElementById('inputfile').click()" style="cursor:pointer;border: 1px solid #AABBCC;" title="点击添加图片" alt="点击添加图片" src="http://f7-preview.awardspace.com/zjmainstay.co.cc/jQueryExample/jquery_upload_image/files/addfile.jpg"> <input type="file" multiple="multiple" id="inputfile" style="height:0;0;z-index: -1; position: absolute;left: 10px;top: 5px;"/> <span class="loading"></span> </div> <div id="feedback"></div> <!-- 响应返回数据容器 --> <script type="text/javascript"> $(document).ready(function(){ //响应文件添加成功事件 $("#inputfile").change(function(){ //创建FormData对象 var data = new FormData(); //为FormData对象添加数据 $.each($('#inputfile')[0].files, function(i, file) { data.append('upload_file'+i, file); }); $(".loading").show(); //显示加载图片 //发送数据 $.ajax({ url:'submit_form_process.php', type:'POST', data:data, cache: false, contentType: false, //不可缺参数 processData: false, //不可缺参数 success:function(data){ data = $(data).html(); //第一个feedback数据直接append,其他的用before第1个( .eq(0).before() )放至最前面。 //data.replace(/</g,'<').replace(/>/g,'>') 转换html标签,否则图片无法显示。 if($("#feedback").children('img').length == 0) $("#feedback").append(data.replace(/</g,'<').replace(/>/g,'>')); else $("#feedback").children('img').eq(0).before(data.replace(/</g,'<').replace(/>/g,'>')); $(".loading").hide(); //加载成功移除加载图片 }, error:function(){ alert('上传出错'); $(".loading").hide(); //加载失败移除加载图片 } }); }); }); </script> </body> </html>
2、submit_form_process.php后台处理文件
功能:对FormData中包含的$_FILES数组做处理并上传图片文件,回传反馈信息。
包含技术:
1)FormData提交至$_FILES后的结构形式
2)iconv('utf-8','gb2312',$filename) 对文件名进行转码处理
3)preg_match("/^.(jpg|jpeg|gif|png){1}$/i", strrchr($gb_filename, '.')) 文件类型过滤
4)move_uploaded_file()上传文件
5)echo '<textarea><img....<img....</textarea>';回传反馈信息。
源码:
<?php header('content-type:text/html charset:utf-8'); $dir_base = "./files/"; //文件上传根目录 //没有成功上传文件,报错并退出。 if(empty($_FILES)) { echo "<textarea><img src='{$dir_base}error.jpg'/></textarea>"; exit(0); } $output = "<textarea>"; $index = 0; //$_FILES 以文件name为数组下标,不适用foreach($_FILES as $index=>$file) foreach($_FILES as $file){ $upload_file_name = 'upload_file' . $index; //对应index.html FomData中的文件命名 $filename = $_FILES[$upload_file_name]['name']; $gb_filename = iconv('utf-8','gb2312',$filename); //名字转换成gb2312处理 //文件不存在才上传 if(!file_exists($dir_base.$gb_filename)) { $isMoved = false; //默认上传失败 $MAXIMUM_FILESIZE = 1 * 1024 * 1024; //文件大小限制 1M = 1 * 1024 * 1024 B; $rEFileTypes = "/^.(jpg|jpeg|gif|png){1}$/i"; if ($_FILES[$upload_file_name]['size'] <= $MAXIMUM_FILESIZE && preg_match($rEFileTypes, strrchr($gb_filename, '.'))) { $isMoved = @move_uploaded_file ( $_FILES[$upload_file_name]['tmp_name'], $dir_base.$gb_filename); //上传文件 } }else{ $isMoved = true; //已存在文件设置为上传成功 } if($isMoved){ //输出图片文件<img>标签 //注:在一些系统src可能需要urlencode处理,发现图片无法显示, // 请尝试 urlencode($gb_filename) 或 urlencode($filename),不行请查看HTML中显示的src并酌情解决。 $output .= "<img src='{$dir_base}{$filename}' title='{$filename}' alt='{$filename}'/>"; }else { $output .= "<img src='{$dir_base}error.jpg' title='{$filename}' alt='{$filename}'/>"; } $index++; } echo $output."</textarea>"; //End_php