找回密码
 立即注册
首页 业界区 业界 拖拽上传图片

拖拽上传图片

玛凶 2025-5-29 16:02:39
 
很久没有写过博客了,闲的时候没东西可写,忙的时候没有时间写。
前些天,后台的同事提建议说,上传图片不是很好用,后台在线编辑器用的是fckeditor。
这时候想到了很久前看过一遍提升用户体验:HTML5 拖放文件上传,于是就打算做一个拖拽上传图片的功能。
因为是后台用,所以不用考虑ie的兼容了。
1.拖图片进浏览器的时候阻止浏览器的默认行为(比如打开直接图片)

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

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

预览图片要用到FileReader
  1. 1 var rd=new FileReader();<br>2 rd.onloadend=function(e){<br>3   var img=document.createElement('img');//创建一个图片<br>4     img.src=this.result;//result就是读出来的内容<br>5     img.width=100;<br>6     img.title=file.name;//文件的原始名称<br>7               <br>8 }<br>9 rd.readAsDataURL({file}); // 读取为dataurl
复制代码
Filereader有下面几种方法,预览图片用到的是readAsDataURL。
方法名参数描述abortnone中断读取readAsBinaryStringfile将文件读取为二进制码readAsDataURLfile将文件读取为 DataURLreadAsTextfile, [encoding]将文件读取为文本 
 
 
 
3.把图片发送到服务端,进行处理

 要提交到服务器,我们必须把图片读取为二进制的格式,这里就用到了Filereader的readAsBinaryString
  1. 1 var reader = new FileReader(); <br> 2         reader.readAsBinaryString({file});<br> 3          <br> 4         reader.onloadend = function(){<br> 5             //bug(this.readyState); // 这个时候 应该是 2<br> 6             //bug(this.result); //读取完成回调函数,数据保存在result中    <br> 7             var fileData=this.result;<br> 8             var CRLF="\r\n";<br> 9             var xhr = new XMLHttpRequest();   <br>10             xhr.open('post', self.server, true);<br>11             //xhr.onreadystatechange=function(){};<br>12             var boundary='------OTkwNzI0OTEx----';//一段随机字符串,最好根据时间来生成,为了分割多个表单项<br>13             // 模拟一个文件提交请求<br>14             xhr.setRequestHeader("Content-Type", "multipart/form-data, boundary="+boundary);<br>15             //xhr.setRequestHeader("Content-Length", file.size);     在chrome下会出错,可能是出于安全考虑,不允许这样做<br>16             var body = '';     <br>17             body += '--' + boundary + CRLF;<br>18             body += 'Content-Disposition: form-data; name="'+{fileFieldName}+'"; filename="' + file.name + '"'+CRLF;     <br>19             body += "Content-Type: "+file.type+CRLF+CRLF;     <br>20             body += fileData + CRLF;     <br>21             body += "--" + boundary + "--"+CRLF;  <br>22             xhr.onreadystatechange = function (aEvt) {  <br>23               if (xhr.readyState == 4) {  <br>24                  if (xhr.status == 200)  <br>25                    alert(xhr.responseText); <br>26                  else  <br>27                    console.log('Error', xhr.statusText);  <br>28               }  <br>29             }; <br>30    <br>31             xhr.sendAsBinary(body);<br>32              <br>33             <br>34             <br>35         }
复制代码
上面代码的第18行filename直接用的原文件名称,并没有改名,这在原名为汉字的情况下会提示错误,应该处理一下,但不知道怎么弄

 
值描述application/x-www-form-urlencoded在发送前编码所有字符(默认)multipart/form-data不对字符编码。
在使用包含文件上传控件的表单时,必须使用该值。
text/plain空格转换为 "+" 加号,但不对特殊字符编码。
上面是在w3cschool搜到的,既然multipart/form-data不对字符编码,但为什么会出错,希望知道的能告诉一声
模拟出来的数据要以二进制发送。火狐XMLHttpRequest 对象中有sendAsBinary()方法,这个是火狐私有的。chrome中没有,但是可以模拟sendAsBinary
  1. 1 XMLHttpRequest.prototype.sendAsBinary = function(datastr) {<br>2                 function byteValue(x) {<br>3                     return x.charCodeAt(0) & 0xff;<br>4                 }<br>5                 var ords = Array.prototype.map.call(datastr, byteValue);<br>6                 var ui8a = new Uint8Array(ords);<br>7                 this.send(ui8a.buffer);<br>8             }
复制代码
服务端接收文件时和普通上传文件时一样
例如php代码:
  1. if(!empty($_FILES)){<br>    $file=$_FILES['new_image'];  //new_image 就是上面的fileFieldName<br>    echo  $file['name'];<br>    move_uploaded_file($file['tmp_name'],"./zf/".$file['name']);<br>    die();<br>}
复制代码
 
 4.显示上传进度
  1. 1 var xhr = new XMLHttpRequest();<br> 2     upload =xhr.upload;<br> 3     upload.addEventListener("progress", updateProgress, false);//updateProgress 处理上传进度     <br> 4     xhr.open('post', “服务端url”, true);<br> 5 <br> 6 function updateProgress(evt) {    <br> 7     if (evt.lengthComputable) {  <br> 8         var percentComplete = Math.round((evt.loaded * 100) / evt.total)<br> 9         bug(percentComplete); <br>10 <br>11     } <br>12     else {  <br>13     // Unable to compute progress information since the total size is unknown  <br>14     }  <br>15 }  
复制代码
 

这个也挺简单,代码如上,不过要注意的是:
1.事件要绑定到 XMLHttpRequest的 upload上,这样才能监听上传进度。 XMLHttpRequest上同时也有progress事件,不过是监听下载的。
2. 火狐和chrome调用updateProgress频率好像一样,具体是每秒调用一次还是怎么着,我也不是很清楚。假如文件很小,而且网络很快(本地测试的,当然快)FF就不会触发progress事件。
   在火狐下, 在上传完成时也不触发事件所以总是导致进度到不了100%,到了百分之80,90就不动了。
 
好了,功能基本都实现了,另外上面那些代码都是我在写篇文章是复制过来的(写了将近一个星期的时间,有空就写,程序基本功能完成是在两个星期前。)。
最后在附上一个我搜索资料过程中找到的一个jquery 插件 jquery-filedrop。
源码下载

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册