拖拽上传图片

拖拽上传图片

 http://www.cnblogs.com/nh11/archive/2011/12/01/2267578.html

很久没有写过博客了,闲的时候没东西可写,忙的时候没有时间写。

前些天,后台的同事提建议说,上传图片不是很好用,后台在线编辑器用的是fckeditor。
这时候想到了很久前看过一遍提升用户体验:HTML5 拖放文件上传,于是就打算做一个拖拽上传图片的功能。

因为是后台用,所以不用考虑ie的兼容了。

1.拖图片进浏览器的时候阻止浏览器的默认行为(比如打开直接图片)

  dropbox 给我们的容器添加上几个事件绑定dragenter,dragover,drop三个事件

 dropbox.addEventListener("dragenter", function(e){ e.stopPropagation(); e.preventDefault(); }, false); 
  dropbox.addEventListener("dragover" , function(e){ e.stopPropagation(); e.preventDefault(); }, false); 
  dropbox.addEventListener("drop", function(e){ 
    e.stopPropagation(); //个人的理解是,若在dropbox上的drop事件被监听多次,则两外的事件绑定无效了(不知道对不对)
    e.preventDefault(); //阻止默认动作
    e.dataTransfer.files//一个file类型的数组,就是你拖拽进来的文件
  }, false);


2.在得到一个文件file后,要把它显示出来

预览图片要用到FileReader

1 var rd=new FileReader();
2 rd.onloadend=function(e){
3   var img=document.createElement('img');//创建一个图片
4     img.src=this.result;//result就是读出来的内容
5     img.width=100;
6     img.title=file.name;//文件的原始名称
7               
8 }
9 rd.readAsDataURL({file}); // 读取为dataurl

Filereader有下面几种方法,预览图片用到的是readAsDataURL。

方法名 参数 描述
abort none 中断读取
readAsBinaryString file 将文件读取为二进制码
readAsDataURL file 将文件读取为 DataURL
readAsText file, [encoding] 将文件读取为文本

 

 

 

 

3.把图片发送到服务端,进行处理

 要提交到服务器,我们必须把图片读取为二进制的格式,这里就用到了Filereader的readAsBinaryString

 1 var reader = new FileReader(); 
 2         reader.readAsBinaryString({file});
 3          
 4         reader.onloadend = function(){
 5             //bug(this.readyState); // 这个时候 应该是 2
 6             //bug(this.result); //读取完成回调函数,数据保存在result中    
 7             var fileData=this.result;
 8             var CRLF="\r\n";
 9             var xhr = new XMLHttpRequest();   
10             xhr.open('post', self.server, true);
11             //xhr.onreadystatechange=function(){};
12             var boundary='------OTkwNzI0OTEx----';//一段随机字符串,最好根据时间来生成,为了分割多个表单项
13             // 模拟一个文件提交请求
14             xhr.setRequestHeader("Content-Type", "multipart/form-data, boundary="+boundary);
15             //xhr.setRequestHeader("Content-Length", file.size);     在chrome下会出错,可能是出于安全考虑,不允许这样做
16             var body = '';     
17             body += '--' + boundary + CRLF;
18             body += 'Content-Disposition: form-data; name="'+{fileFieldName}+'"; filename="' + file.name + '"'+CRLF;     
19             body += "Content-Type: "+file.type+CRLF+CRLF;     
20             body += fileData + CRLF;     
21             body += "--" + boundary + "--"+CRLF;  
22             xhr.onreadystatechange = function (aEvt) {  
23               if (xhr.readyState == 4) {  
24                  if (xhr.status == 200)  
25                    alert(xhr.responseText); 
26                  else  
27                    console.log('Error', xhr.statusText);  
28               }  
29             }; 
30    
31             xhr.sendAsBinary(body);
32              
33             
34             
35         }

上面代码的第18行filename直接用的原文件名称,并没有改名,这在原名为汉字的情况下会提示错误,应该处理一下,但不知道怎么弄

 

描述
application/x-www-form-urlencoded 在发送前编码所有字符(默认)
multipart/form-data

不对字符编码。

在使用包含文件上传控件的表单时,必须使用该值。

text/plain 空格转换为 "+" 加号,但不对特殊字符编码。


上面是在w3cschool搜到的,既然multipart/form-data不对字符编码,但为什么会出错,希望知道的能告诉一声
模拟出来的数据要以二进制发送。火狐XMLHttpRequest 对象中有sendAsBinary()方法,这个是火狐私有的。chrome中没有,但是可以模拟sendAsBinary

1 XMLHttpRequest.prototype.sendAsBinary = function(datastr) {
2                 function byteValue(x) {
3                     return x.charCodeAt(0) & 0xff;
4                 }
5                 var ords = Array.prototype.map.call(datastr, byteValue);
6                 var ui8a = new Uint8Array(ords);
7                 this.send(ui8a.buffer);
8             }

服务端接收文件时和普通上传文件时一样
例如php代码:

if(!empty($_FILES)){
    $file=$_FILES['new_image'];  //new_image 就是上面的fileFieldName
    echo  $file['name'];
    move_uploaded_file($file['tmp_name'],"./zf/".$file['name']);
    die();
}

 

 4.显示上传进度

 1 var xhr = new XMLHttpRequest();
 2     upload =xhr.upload;
 3     upload.addEventListener("progress", updateProgress, false);//updateProgress 处理上传进度     
 4     xhr.open('post', “服务端url”, true);
 5 
 6 function updateProgress(evt) {    
 7     if (evt.lengthComputable) {  
 8         var percentComplete = Math.round((evt.loaded * 100) / evt.total)
 9         bug(percentComplete); 
10 
11     } 
12     else {  
13     // Unable to compute progress information since the total size is unknown  
14     }  
15 }  

 

这个也挺简单,代码如上,不过要注意的是:

1.事件要绑定到 XMLHttpRequest的 upload上,这样才能监听上传进度。 XMLHttpRequest上同时也有progress事件,不过是监听下载的。
2. 火狐和chrome调用updateProgress频率好像一样,具体是每秒调用一次还是怎么着,我也不是很清楚。假如文件很小,而且网络很快(本地测试的,当然快)FF就不会触发progress事件。
   在火狐下, 在上传完成时也不触发事件所以总是导致进度到不了100%,到了百分之80,90就不动了。

 

好了,功能基本都实现了,另外上面那些代码都是我在写篇文章是复制过来的(写了将近一个星期的时间,有空就写,程序基本功能完成是在两个星期前。)
最后在附上一个我搜索资料过程中找到的一个jquery 插件 jquery-filedrop

源码下载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值