最近看了一些jQuery即时上传的插件,总算看懂了些门路。现将其最为核心的一部分抽取出来,以期用最简单的例子来说明jQuery图片即时上传的原理。
首先本用例一共包含3个文件:
1、上传面板HTML文件。
2、上传处理PHP文件。
3、jQuery库。
第一、上传面板HTML文件(index.html)。
其主要包含了jQuery库、即时上传所需js、表单和iframe框架。下面是其源码,其中已附详细注释。
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <title>jQuery Upload Image</title> 5 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 6 <meta http-equiv="Content-Language" content="zh-CN" /> 7 <!--<script type="text/javascript" src="jquery-1.6.2.min.js"></script>--> <!-- 本地jquery库--> 8 <script type="text/javascript" src="http://files.cnblogs.com/Zjmainstay/jquery-1.6.2.min.js"></script> 9 </head> 10 <body> 11 <style> 12 #exec_target{display:none;width:0;height:0;} 13 #feedback{width:1200px;margin:0 auto;} 14 #feedback img{float:left;width:300px;height:300px;} 15 </style> 16 <script type="text/javascript"> 17 $(document).ready(function(){ 18 //选择文件成功则提交表单 19 $("#upload_file").change(function(){ 20 if($("#upload_file").val() != '') $("#submit_form").submit(); 21 }); 22 //iframe加载响应,初始页面时也有一次,此时data为null。 23 $("#exec_target").load(function(){ 24 var data = $(window.frames['exec_target'].document.body).find("textarea").html(); 25 //若iframe携带返回数据,则显示在feedback中 26 if(data != null){ 27 $("#feedback").append(data.replace(/</g,'<').replace(/>/g,'>')); 28 $("#upload_file").val(''); 29 } 30 }); 31 }); 32 </script> 33 <form id="submit_form" method="post" action="submit_form_process.php" target="exec_target" enctype="multipart/form-data"> 34 <input type="file" name="upload_file" id="upload_file"> <!-- 添加上传文件 --> 35 </form> 36 <iframe id="exec_target" name="exec_target"></iframe> <!-- 提交表单处理iframe框架 --> 37 <div id="feedback"></div> <!-- 响应返回数据容器 --> 38 </body> 39 </html>
第二、上传处理PHP文件(submit_form_process.php)。
其主要包含了图片文件的简单上传,及返回图片标签<img>,其中存储刚上传的图片。下面是其源码。
1 <?php 2 //header('content-type:text/html charset:utf-8'); /* 这句要删除,否则可能会导致IE下回传HTML变成下载 */ 3 //不存在当前上传文件则上传 4 if(!file_exists($_FILES['upload_file']['name'])) move_uploaded_file($_FILES['upload_file']['tmp_name'],iconv('utf-8','gb2312',$_FILES['upload_file']['name'])); 5 //输出图片文件<img>标签 6 echo "<textarea><img src='{$_FILES['upload_file']['name']}'/></textarea>"; 7 //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即时上传示例
演示地址: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”,直接不能运行。
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <title>FormData</title> 5 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 6 <meta http-equiv="Content-Language" content="zh-CN" /> 7 <script type="text/javascript" src="http://files.cnblogs.com/Zjmainstay/jquery-1.6.2.min.js"></script> 8 </head> 9 <body> 10 <style> 11 #feedback{width:1200px;margin:0 auto;} 12 #feedback img{float:left;width:300px;height:300px;} 13 </style> 14 <div> 15 <!-- 点击图片添加文件方式 --> 16 <img src="http://f7-preview.awardspace.com/zjmainstay.co.cc/jQueryExample/jquery_upload_image/files/addfile.jpg" onclick="getElementById('inputfile').click()" title="点击添加图片" alt="点击添加图片"> 17 <input type="file" name="image" style="opacity:0;filter:alpha(opacity=0);" id="inputfile"/> 18 </div> 19 <div id="feedback"></div> <!-- 响应返回数据容器 --> 20 <script type="text/javascript"> 21 $(document).ready(function(){ 22 $("#inputfile").change(function(){ 23 //创建FormData对象 24 var data = new FormData(); 25 //为FormData对象添加数据 26 // 27 $.each($('#inputfile')[0].files, function(i, file) { 28 data.append('upload_file', file); 29 }); 30 $.ajax({ 31 url:'submit_form_process.php', 32 type:'POST', 33 data:data, 34 cache: false, 35 contentType: false, //不可缺 36 processData: false, //不可缺 37 success:function(data){ 38 data = $(data).html(); 39 if($("#feedback").children('img').length == 0) $("#feedback").append(data.replace(/</g,'<').replace(/>/g,'>')); 40 else $("#feedback").children('img').eq(0).before(data.replace(/</g,'<').replace(/>/g,'>')); 41 } 42 }); 43 }); 44 }); 45 </script> 46 </body> 47 </html>
演示地址:Ajax FormData 提交表单
/*************************************** 追加2 ***************************************/
多图上传实现(独立于上面两个版本的文件):
1、index.html文件
功能:点击图片添加文件、添加多个文件、即时上传文件、显示上传文件反馈信息。
包含技术:
1)$.ajax
2)$.ajax 发送FormData对象
3)input multiple="multiple"上传多个文件
4)img οnclick="getElementById('inputfile').click()" 点击图片实现添加文件操作
5)input type="file" 样式:height:0;width:0;z-index: -1;隐藏添加文件按钮(Chrome下使用display:none会导致点击失效)
源码:
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <title>Easy Ajax FormData Upload Multiple Images</title> 5 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 6 <meta http-equiv="Content-Language" content="zh-CN" /> 7 <script type="text/javascript" src="http://files.cnblogs.com/Zjmainstay/jquery-1.6.2.min.js"></script> 8 </head> 9 <body> 10 <style> 11 #feedback{width:1200px;margin:0 auto;} 12 #feedback img{float:left;width:300px;height:300px;} 13 #ZjmainstaySignaturePicture,#addpicContainer{float:left;width: 100%;} 14 #addpicContainer{margin-left:5px;} 15 #ZjmainstaySignaturePicture img{width: 535px;} 16 #addpicContainer img{float: left;} 17 .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;} 18 </style> 19 <div id="ZjmainstaySignaturePicture"><a href="http://www.cnblogs.com/Zjmainstay"><img src="http://pic002.cnblogs.com/images/2012/383557/2012071311244097.jpg"/></a></div> 20 <div id="addpicContainer"> 21 <!-- 利用multiple="multiple"属性实现添加多图功能 --> 22 <!-- position: absolute;left: 10px;top: 5px;只针对本用例将input隐至图片底下。--> 23 <!-- height:0;width:0;z-index: -1;是为了隐藏input,因为Chrome下不能使用display:none,否则无法添加文件 --> 24 <!-- οnclick="getElementById('inputfile').click()" 点击图片时则点击添加文件按钮 --> 25 <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"> 26 <input type="file" multiple="multiple" id="inputfile" style="height:0;width:0;z-index: -1; position: absolute;left: 10px;top: 5px;"/> 27 <span class="loading"></span> 28 </div> 29 <div id="feedback"></div> <!-- 响应返回数据容器 --> 30 <script type="text/javascript"> 31 $(document).ready(function(){ 32 //响应文件添加成功事件 33 $("#inputfile").change(function(){ 34 //创建FormData对象 35 var data = new FormData(); 36 //为FormData对象添加数据 37 $.each($('#inputfile')[0].files, function(i, file) { 38 data.append('upload_file'+i, file); 39 }); 40 $(".loading").show(); //显示加载图片 41 //发送数据 42 $.ajax({ 43 url:'submit_form_process.php', 44 type:'POST', 45 data:data, 46 cache: false, 47 contentType: false, //不可缺参数 48 processData: false, //不可缺参数 49 success:function(data){ 50 data = $(data).html(); 51 //第一个feedback数据直接append,其他的用before第1个( .eq(0).before() )放至最前面。 52 //data.replace(/</g,'<').replace(/>/g,'>') 转换html标签,否则图片无法显示。 53 if($("#feedback").children('img').length == 0) $("#feedback").append(data.replace(/</g,'<').replace(/>/g,'>')); 54 else $("#feedback").children('img').eq(0).before(data.replace(/</g,'<').replace(/>/g,'>')); 55 $(".loading").hide(); //加载成功移除加载图片 56 }, 57 error:function(){ 58 alert('上传出错'); 59 $(".loading").hide(); //加载失败移除加载图片 60 } 61 }); 62 }); 63 }); 64 </script> 65 </body> 66 </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>';回传反馈信息。
源码:
1 <?php 2 header('content-type:text/html charset:utf-8'); 3 $dir_base = "./files/"; //文件上传根目录 4 //没有成功上传文件,报错并退出。 5 if(empty($_FILES)) { 6 echo "<textarea><img src='{$dir_base}error.jpg'/></textarea>"; 7 exit(0); 8 } 9 10 $output = "<textarea>"; 11 $index = 0; //$_FILES 以文件name为数组下标,不适用foreach($_FILES as $index=>$file) 12 foreach($_FILES as $file){ 13 $upload_file_name = 'upload_file' . $index; //对应index.html FomData中的文件命名 14 $filename = $_FILES[$upload_file_name]['name']; 15 $gb_filename = iconv('utf-8','gb2312',$filename); //名字转换成gb2312处理 16 //文件不存在才上传 17 if(!file_exists($dir_base.$gb_filename)) { 18 $isMoved = false; //默认上传失败 19 $MAXIMUM_FILESIZE = 1 * 1024 * 1024; //文件大小限制 1M = 1 * 1024 * 1024 B; 20 $rEFileTypes = "/^\.(jpg|jpeg|gif|png){1}$/i"; 21 if ($_FILES[$upload_file_name]['size'] <= $MAXIMUM_FILESIZE && 22 preg_match($rEFileTypes, strrchr($gb_filename, '.'))) { 23 $isMoved = @move_uploaded_file ( $_FILES[$upload_file_name]['tmp_name'], $dir_base.$gb_filename); //上传文件 24 } 25 }else{ 26 $isMoved = true; //已存在文件设置为上传成功 27 } 28 if($isMoved){ 29 //输出图片文件<img>标签 30 //注:在一些系统src可能需要urlencode处理,发现图片无法显示, 31 // 请尝试 urlencode($gb_filename) 或 urlencode($filename),不行请查看HTML中显示的src并酌情解决。 32 $output .= "<img src='{$dir_base}{$filename}' title='{$filename}' alt='{$filename}'/>"; 33 }else { 34 $output .= "<img src='{$dir_base}error.jpg' title='{$filename}' alt='{$filename}'/>"; 35 } 36 37 $index++; 38 } 39 40 echo $output."</textarea>"; 41 42 //End_php
软件包下载:PHP jQuery多图上传实现源文件
演示地址:PHP jQuery多图上传演示