html5拖拽图片批量ajax无刷新进度上传

标签: html5 图片 ajax | 发表时间:2014-08-19 00:38 | 作者:天梯梦
出处:http://www.iteye.com

1、前端拖拽图片

之前有篇文章说到HTML5的拖拽( dragdrop,详见: /post/jquery-plugin-1-jquery-drag-and-html5-draggable-api-and-compatibility.html)。这里说的拖拽图片只是弱化了拖的概念,而强化了拽的操作。从浏览器外部拖动一个文件到浏览器中来,如:

拖动文件到浏览器之后,就会打开浏览器支持的文件,如常用的txt、图片等,如下:

操作如上常用文件,一般都有默认行为来处理这样的事件。这里说的拖拽上传也是一个道理,就是要做的是从浏览器外部拖动文件到浏览器中来,并且在当前页面上传该文件。在表面上看来,这个方法很适合用户体验,但实际情况是用户体验急剧下降。因为大多数人浏览网页的时候是全最大化窗口查看的,而如果要拖拽上传文件的话,那么就需要把浏览器窗口后,非常的麻烦。就比如wordpress的添加媒体功能,也是支持拖拽上传图片的,可用过的人又有多少呢?

倒还不如点击选择图片操作来的更加快捷,不过本文旨在说明问题。也许有更好玩的例子没有被发现而已,在此只做抛砖引玉。

1.1、拖拽文件的files对象

在拖拽文件到浏览器,我们需要处理这些文件。

$.fn.listen=function(type,fn){
	returnthis.each(function(){
		$(this)[0].addEventListener(type,function(e){
			if(!fn.call($(this),e)){
				e.stopPropagation();
				e.preventDefault();
			}
		},0);
	});
}
$(document).bind("dragenter",function(){
	returnfalse;
}).bind("dragover",function(){
	returnfalse;
}).listen("drop",function(e){
	// 这里处理拖拽进来的文件(们)
});

 

如上,可能细心的朋友发现了一些不同。那就是document使用了两个方法来绑定事件, dragenterdragover使用jquery的 bind方法绑定,而drop事件却使用自定义的 listen方法绑定,这是为什么呢?因为jquery的事件绑定,为了兼容操作处理的事件的参数event,删减了一些属性使其在各个浏览器都保持一致。而此处用的是event的HTML5属性,恰巧是不兼容低级浏览器的,所以使用jquery的 bind方法是无法获取的。我们可以来验证一下这个说法:

$(document).bind("dragenter",function(){
	returnfalse;
}).bind("dragover",function(){
	returnfalse;
}).bind("drop",function(e){
	console.log(e);
}).listen("drop",function(e){
	console.log(e);
});

 

拖拽文件到这个页面,在浏览器控制台得到两个不尽相同的对象:

如图示黄色背景的 dataTransfer是浏览器默认的event所独有的,而我们此处用的 files对象这是在这里面。

console.log(e.dataTransfer.files);

 

在浏览器控制台输出了:

由图示可知,该files对象是一个数组。 值得注意的是,该files对象只读。可以接收到文件的基本信息(最后修改时间、文件名称、大小、类型),我们就可以在客户端来处理上传文件之前的操作。比如限制文件必须为图片格式、文件的大小不能超过100KB。

$(document).bind("dragenter",function(){
	returnfalse;
}).bind("dragover",function(){
	returnfalse;
}).listen("drop",function(e){
    var files=e.dataTransfer.files;
    var error='';
    for(var i=0;i<files.length;i++){
    console.log(files[i]);
    if(files[i].size>1024*100)error+='第'+(i+1)+'个文件超过大小限制\n';
    if(!/image/i.test(files[i].type))error+='第'+(i+1)+'个文件不是图片格式\n';
}
if(error)alert(error);
});

 

会弹出如下警告:

1.2、处理文件的FileReader对象

用户拖拽了符合我们预期的文件,我们就需要对其进行操作。比如本文要做的是用户必须上传100KB以内的图片类型文件。在获取到files对象之后,我们要使用 FileReader对象来读取file的文件(该对象人如其名)。

$(document).bind("dragenter",function(){
	returnfalse;
}).bind("dragover",function(){
	returnfalse;
}).listen("drop",function(e){
    var files=e.dataTransfer.files;
    var error='';
    for(var i=0;i<files.length;i++){
    if(files[i].size>1024*100)error+='第'+(i+1)+'个文件超过大小限制\n';
    if(!/image/i.test(files[i].type))error+='第'+(i+1)+'个文件不是图片格式\n';
}
// 有错误抛弃
if(error){
    alert(error);
    return;
}
// 处理文件队列
for(var i=0;i<files.length;i++){
	read(files[i]);
}
});
function read(file){
	var reader=newFileReader();
 	reader.onload=function(e){
		$("body").append('<img src="'+e.target.result+'" alt="" />');
	}
	reader.readAsDataURL(file);
}

 

在拖拽合适大小的图片文件到该页面之后:

FileReader对象是干嘛的呢?它可以读取文件,并进行相应的操作,涉及到安全问题,该操作不会对图片的源文件产生影响。该对象有如下属性和方法以及事件:

  • 属性:为空
  • 方法:
    • about:中断文件读取
    • readAsBinaryString:读取文件为二进制
    • readAsDataURL:读取文件dataUrl(本例用到的)
    • readAsText:读取文件为文本
  • 事件:
    • onabort:读取文件中断时触发
    • onerror:读取文件出错时触发
    • onload:读取文件成功时触发(本例用到的)
    • onloadstart:读取文件开始时触发
    • onprogress:读取文件中时一直触发
    • onloadend:读取文件结束时触发(成功和失败都会触发,如 jquery.ajaxcomplete

在监听到文件读取成功时,该事件参数e有 e.target.result指向的是读取的结果(即本例描述的文件的二进制url)。

1.3、处理表单的FormData对象

选到了合适大小的图片文件,我们就需要把这些文件无刷新上传到服务器,但我们如何发送这些图片到后端呢?传统的ajax方法一直是发送文本格式(Content-Type:application/x-www-form-urlencoded)而发送图片这些大文件需要用到浏览器的原生表单(Content-Type:multipart/form-data)。所幸的是,HTML5的支持的 FromData属性可以帮忙完成这一个过程,即封装图片成表单数据以用于提交到后端。

FormData类似于 jquery.serialize,jquery这一次又走在了前列。不过 FormDataserialize要强大一点,它不仅可以在提交表单数据里增加纯文本也可以增加图片等二进制数据。其基本使用方法是:

  1. var form1=newFormData();
  2. form1.append("name1","value1");
  3. form1.append("name2","value2");
  4. form1.append("file",file对象);

如上,其作用相当于:

  1. <form>
  2. <inputtype="text"name="name1"value="value1">
  3. <inputtype="text"name="name2"value="value2">
  4. <inputtype="file"name="file"id="">
  5. </form>

所以接着1.2继续,把合适的图片组装成form数据便于异步传输。

  1. $(document).bind("dragenter",function(){
  2. returnfalse;
  3. }).bind("dragover",function(){
  4. returnfalse;
  5. }).listen("drop",function(e){
  6. var files=e.dataTransfer.files;
  7. var error='';
  8. for(var i=0;i<files.length;i++){
  9. if(files[i].size>1024*100)error+='第'+(i+1)+'个文件超过大小限制\n';
  10. if(!/image/i.test(files[i].type))error+='第'+(i+1)+'个文件不是图片格式\n';
  11. }
  12. // 有错误抛弃
  13. if(error){
  14. alert(error);
  15. return;
  16. }
  17. // 处理文件队列
  18. for(var i=0;i<files.length;i++){
  19. read(files[i]);
  20. }
  21. // 组装成表单数据
  22. var formData=newFormData();
  23. for(var i=0;i<files.length;i++){
  24. formData.append('files[]',files[i]);
  25. }
  26. });
  27. // 读取图片
  28. function read(file){
  29. var reader=newFileReader();
  30. reader.onload=function(e){
  31. $("body").append('<img src="'+e.target.result+'" alt="" />');
  32. }
  33. reader.readAsDataURL(file);
  34. }

注:以上代码仅供示例,上述的 formData.append('files[]',...),有中括号表示多文件批量上传。

1.4、ajax上传的XMLHttpRequest对象

有了表单数据,我们就可以使用异步传输发送给服务端。

  1. $(document).bind("dragenter",function(){
  2. returnfalse;
  3. }).bind("dragover",function(){
  4. returnfalse;
  5. }).listen("drop",function(e){
  6. var files=e.dataTransfer.files;
  7. var error='';
  8. for(var i=0;i<files.length;i++){
  9. if(files[i].size>1024*100)error+='第'+(i+1)+'个文件超过大小限制\n';
  10. if(!/image/i.test(files[i].type))error+='第'+(i+1)+'个文件不是图片格式\n';
  11. }
  12. // 有错误抛弃
  13. if(error){
  14. alert(error);
  15. return;
  16. }
  17. // 处理文件队列
  18. for(var i=0;i<files.length;i++){
  19. read(files[i]);
  20. }
  21. // 组装成表单数据
  22. var formData=newFormData();
  23. for(var i=0;i<files.length;i++){
  24. formData.append('files[]',files[i]);
  25. }
  26. // 异步传输
  27. ajax();
  28. });
  29. // 读取图片
  30. function read(file){
  31. var reader=newFileReader();
  32. reader.onload=function(e){
  33. $("body").append('<img src="'+e.target.result+'" alt="" />');
  34. }
  35. reader.readAsDataURL(file);
  36. }
  37. // 异步传输
  38. function ajax(formData){
  39. var xhr=newXMLHttpRequest();
  40. xhr.open("post","upload.php");
  41. xhr.onload=function(){
  42. alert("上传完成!");
  43. }
  44. xhr.send(formData);
  45. }

如果上传不出错的话,那么在上传结束的时候会弹出“上传完成!”的确认框。

1.5、ajax上传的进度

因为上传文件和上传纯文本,其数据量不是一个级别的,所以为了友好的用户体验,我们需要实时告诉用户上传的进度目前是多少。可喜的是,HTML5已经帮我们完成这个步骤,可以这么做来实时获取当前上传的进度:

  1. // 异步传输
  2. function ajax(formData){
  3. var xhr=newXMLHttpRequest();
  4. xhr.open("post","upload.php");
  5. xhr.onload=function(){
  6. alert("上传完成!");
  7. }
  8. // 上传进度
  9. xhr.upload.onprogress=function(e){
  10. if(e.lengthComputable){
  11. var percent =(e.loaded / e.total *100|0)+"%";
  12. console.log(percent);
  13. }
  14. }
  15. xhr.send(formData);
  16. }

关于 XMLHttpRequest的更多使用方法,这里不做赘述,可以参考文章末尾的参考资料。

1.6、完整的源代码

  1. <!doctype html>
  2. <htmllang="en">
  3. <head>
  4. <metacharset="UTF-8">
  5. <title>拖拽图片到这里来并上传</title>
  6. <style>
  7. h2 small{
  8. color:#888;
  9. font-weight: normal;
  10. margin-left:30px;
  11. font-size:80%;
  12. }
  13. .box{
  14. border:1px solid #ccc;
  15. background:#f5f5f5;
  16. padding:10px;
  17. margin-bottom:20px;
  18. }
  19. .box2{
  20. border:1px solid #EB9D45;
  21. background:#FFF2E3;
  22. padding:10px;
  23. margin-bottom:20px;
  24. }
  25. #progress{
  26. margin-left:10px;
  27. }
  28. .box img,
  29. .box2 img{
  30. max-height:100px;
  31. height:auto;
  32. width:auto;
  33. padding:2px;
  34. border:1px solid #ddd;
  35. background:#fff;
  36. margin-right:20px;
  37. margin-bottom:20px;
  38. }
  39. </style>
  40. </head>
  41. <body>
  42. <divclass="box">
  43. <h2>拖拽图片到这里来<smallid="message"></small></h2>
  44. <divid="box"></div>
  45. </div>
  46. <p>原文:<ahref="/post/undefined.html700">/post/undefined.html700</a></p>
  47. <divclass="box2">
  48. <h2>已上传的图片<smallid="progress"></small></h2>
  49. <divid="box2"></div>
  50. </div>
  51. <scriptsrc="http://libs.baidu.com/jquery/2.0.3/jquery.min.js"></script>
  52. <script>
  53. $.fn.listen=function(type,fn){
  54. returnthis.each(function(){
  55. $(this)[0].addEventListener(type,function(e){
  56. if(!fn.call($(this),e)){
  57. e.stopPropagation();
  58. e.preventDefault();
  59. }
  60. },0);
  61. });
  62. }
  63. var $box=$("#box");
  64. var $message=$("#message");
  65. var $box2=$("#box2");
  66. var $progress=$("#progress");
  67. var isuploading=0;
  68. var hasBtSize=0;
  69. var errorArray=[];
  70. $(document).bind("dragenter",function(){
  71. returnfalse;
  72. }).bind("dragover",function(){
  73. returnfalse;
  74. }).listen("drop",function(e){
  75. if(isuploading)return;
  76. var error='';
  77. var num=1;
  78. var files=e.dataTransfer.files;
  79. var j=files.length;
  80. $box.empty();
  81. for(var i =0; i < j; i++){
  82. (function(i){
  83. var reader =newFileReader();
  84. reader.onload =function(event){
  85. $box.append("<img src='"+ event.target.result +"' /> ");
  86. if(files[i].size>1024*400||!/image/.test(files[i].type)){
  87. errorArray.push(num);
  88. }
  89. num++;
  90. if(num>j){
  91. if(errorArray.length){
  92. error=errorArray.join(',');
  93. $message.html("其中第 "+error+" 个文件大小超过限制或不是图片,本次上传已被取消。");
  94. errorArray=[];
  95. return;
  96. }
  97. upload(files);
  98. }
  99. };
  100. reader.readAsDataURL(files[i]);
  101. })(i);
  102. }
  103. returnfalse;
  104. });
  105. function upload(files){
  106. if(isuploading)return;
  107. isuploading=1;
  108. var formData=newFormData();
  109. var isComplete=0;
  110. for(var i=0; i <files.length; i++){
  111. formData.append("files[]",files[i]);
  112. };
  113. var xhr=newXMLHttpRequest();
  114. xhr.open('post','upload.php');
  115. xhr.onload=function(){
  116. $progress.html("上传完成!");
  117. };
  118. xhr.onreadystatechange=function(){
  119. if(xhr && xhr.readyState ===4){
  120. status = xhr.status;
  121. if(!isComplete && status >=200&& status <300|| status ===304){
  122. isComplete =true;
  123. var json=$.parseJSON(xhr.responseText);
  124. $box2.empty();
  125. $box.empty();
  126. $message.empty();
  127. $.each(json,function(key,val){
  128. $box2.append("<img src='"+ val +"' />");
  129. });
  130. isuploading=0;
  131. }elseif(!isComplete){
  132. isComplete =true;
  133. $box.html("网络错误!");
  134. isuploading=0;
  135. }
  136. xhr =null;
  137. }
  138. }
  139. xhr.upload.onprogress =function(event){
  140. if(event.lengthComputable){
  141. var percent =(event.loaded / event.total *100|0)+"%";
  142. $progress.html(percent);
  143. }
  144. }
  145. xhr.send(formData);
  146. }
  147. </script>
  148. </body>
  149. </html>

在上传过程中:

2、后台上传处理

  1. <?php
  2. $uploaddir ='img/';
  3. $src_array=array();
  4. if(isset($_FILES['files'])){
  5. foreach($_FILES['files']["error"]as $key => $error){
  6. if($error==UPLOAD_ERR_OK){
  7. if(!preg_match("#image#",$_FILES["files"]["type"][$key]))continue;
  8. if($_FILES["files"]["size"][$key]>1024*400)continue;
  9. $tmp_name = $_FILES["files"]["tmp_name"][$key];
  10. $name = $_FILES["files"]["name"][$key];
  11. $name= date("YmdHis",time()).preg_replace("#[^\w\.]#","",$name);
  12. $uploadfile = $uploaddir.$name;
  13. $ret=move_uploaded_file($tmp_name, $uploadfile);
  14. if($ret){
  15. $src_array[]=$uploadfile;
  16. }
  17. }
  18. }
  19. }
  20. echo json_encode($src_array);

3、demo

demo地址: http://demo.qianduanblog.com/2700/1.html

jquery批量上传插件详细见: /post/jquery-plugin-11-jquery-upload-free-refresh-batch-ajax-progress-upload.html

4、参考资料

 

 



已有 0 人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



相关 [html5 图片 ajax] 推荐:

基于HTML5的可预览多图片Ajax上传

- Lynn - 张鑫旭-鑫空间-鑫生活
本文地址:http://www.zhangxinxu.com/wordpress/?p=1923. 在XHTML的时代,我们使用HTML file控件上传图片一次只能上传一张. 要一次上传多图,做法是借助于flash. 可惜,使用复杂的点,比如flash文件需与页面同父文件夹,JavaScript文件大小也很可观.

html5拖拽图片批量ajax无刷新进度上传

- - Web前端 - ITeye博客
之前有篇文章说到HTML5的拖拽(. 这里说的拖拽图片只是弱化了拖的概念,而强化了拽的操作. 从浏览器外部拖动一个文件到浏览器中来,如:. 拖动文件到浏览器之后,就会打开浏览器支持的文件,如常用的txt、图片等,如下:. 操作如上常用文件,一般都有默认行为来处理这样的事件. 这里说的拖拽上传也是一个道理,就是要做的是从浏览器外部拖动文件到浏览器中来,并且在当前页面上传该文件.

ajax与HTML5 history pushState/replaceState实例

- - 张鑫旭-鑫空间-鑫生活
本文地址: http://www.zhangxinxu.com/wordpress/?p=3432. 我就TM想找个例子,知道如何个使用,使用语法什么的滚粗. 精力总是有限的,昨天一冲动,在上海浦东外环之外订了个90米的房子,要借钱筹首付、贷款和领证什么的. HTML5 history相关知识点啪啦啪啦讲起来也是一条又臭又长的裹脚布,精气神实在不够用,这里,直接一个实例.

利用jQuery和HTML5实现无刷新Ajax风格的表单

- - CSDN博客推荐文章
        利用jQuery我们能够做出一些相当震撼的网页效果. jQuery的出现使DOM的操作更加的简单易用. 下面的教程展示了如何利用jQuery创建一个HTML5效果的邀请表格,同时实现表格内容的检查功能.         首页的格式必须是HTML5的格式.         接下来添加jQuery库,将如下代码添加到标签之前:.

html5 图片上传预览

- - 博客园_首页
  前段时间做html5项目的时候,做了一个图片上传功能,并且可以直接预览,单纯的js就可以实现,很方便的.   这样做比调用后台方便多了,但是只支持html5的,html5以前是不支持的. 未来html5是主流,所以这种方法非常方便的.   几段js代码就可以来实现,而且解析速度也很快. 这种方法值得推广,以后前端也不要为这个烦恼了,还要后台用程序加载出来,那样太浪费时间了.

HTML5本地裁剪图片

- - SegmentFault 最新的文章
我们首先需要创建一个 index.html文件,里面写上一些简单的 html和 css代码:. 以上的三个 标签都是用来处理跟图片相关的内容的,详细的处理会在后续的js代码中给出. 而 id为 show_edit 和 id为 show_pic这两个是为了图片的预览和查看最后的图片生成结果.

原生AJAX

- - Web前端 - ITeye博客
对象是ajax的基础,几乎所有的浏览器都支持他,只是创建方式不同,如IE5,IE6. 2、AJAX - 向服务器发送请求请求. 与 POST 相比,GET 更简单也更快,并且在大部分情况下都能用. 然而,在以下情况中,请使用 POST 请求:. 无法使用缓存文件(更新服务器上的文件或数据库). 向服务器发送大量数据(POST 没有数据量限制).

初识Ajax

- - CSDN博客推荐文章
Ajax(Asynchronous JavaScript and XMLS异步JavaScript和XML)(“阿贾克斯”)技术. 完成页面的局部刷新,从而提升操作性能. AJAX 不是一种新的编程语言,而是一种用于创建更好更快以及交互性更强的 Web 应用程序的技术. 依赖的核心对象:XMLHttpRequest.

Ajax上传图片以及上传之前先预览 - 江南一点雨的专栏 - CSDN博客

- -
手头上有几个小项目用到了easyUI,一开始决定使用easyUI就注定了项目整体上前后端分离,基本上所有的请求都采用Ajax来完成. 在文件上传的时候用到了Ajax上传文件,以及图片在上传之前的预览效果,解决了这两个小问题,和小伙伴们分享下. 先来说说图片上传之前的预览问题. 这里主要采用了HTML5中的FileReader对象来实现,关于FileReader对象,如果小伙伴们不了解,可以查看这篇博客HTML5学习之FileReader接口.

CSS 与 HTML5 响应式图片

- - TaoBaoUED
 随着  Retina 屏幕的逐渐普及,网页中对图片的适配要求也越来越高. 如何让图片在放大了两倍的 Retina 屏幕显示依然清晰,曾经一度困扰着网页开发者,好在 CSS3 与 HTML5 已经着力在改变这种现状. 响应式图片是指: 用户代理根据输出设备的分辨率不同加载不同类型的图片,不会造成带宽的浪费.