拖拽上傳圖片
很久沒有寫過博客了,閑的時(shí)候沒東西可寫,忙的時(shí)候沒有時(shí)間寫。
前些天,后臺(tái)的同事提建議說,上傳圖片不是很好用,后臺(tái)在線編輯器用的是fckeditor。
這時(shí)候想到了很久前看過一遍提升用戶體驗(yàn):HTML5 拖放文件上傳,于是就打算做一個(gè)拖拽上傳圖片的功能。
因?yàn)槭呛笈_(tái)用,所以不用考慮ie的兼容了。
1.拖圖片進(jìn)瀏覽器的時(shí)候阻止瀏覽器的默認(rèn)行為(比如打開直接圖片)
dropbox 給我們的容器添加上幾個(gè)事件綁定dragenter,dragover,drop三個(gè)事件
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(); //個(gè)人的理解是,若在dropbox上的drop事件被監(jiān)聽多次,則兩外的事件綁定無效了(不知道對不對)
e.preventDefault(); //阻止默認(rèn)動(dòng)作
e.dataTransfer.files//一個(gè)file類型的數(shù)組,就是你拖拽進(jìn)來的文件
}, false);
2.在得到一個(gè)文件file后,要把它顯示出來
預(yù)覽圖片要用到FileReader
1 var rd=new FileReader();
2 rd.onloadend=function(e){
3 var img=document.createElement('img');//創(chuàng)建一個(gè)圖片
4 img.src=this.result;//result就是讀出來的內(nèi)容
5 img.width=100;
6 img.title=file.name;//文件的原始名稱
7
8 }
9 rd.readAsDataURL({file}); // 讀取為dataurl
Filereader有下面幾種方法,預(yù)覽圖片用到的是readAsDataURL。
| 方法名 | 參數(shù) | 描述 |
|---|---|---|
| abort | none | 中斷讀取 |
| readAsBinaryString | file | 將文件讀取為二進(jìn)制碼 |
| readAsDataURL | file | 將文件讀取為 DataURL |
| readAsText | file, [encoding] | 將文件讀取為文本 |
3.把圖片發(fā)送到服務(wù)端,進(jìn)行處理
要提交到服務(wù)器,我們必須把圖片讀取為二進(jìn)制的格式,這里就用到了Filereader的readAsBinaryString
1 var reader = new FileReader();
2 reader.readAsBinaryString({file});
3
4 reader.onloadend = function(){
5 //bug(this.readyState); // 這個(gè)時(shí)候 應(yīng)該是 2
6 //bug(this.result); //讀取完成回調(diào)函數(shù),數(shù)據(jù)保存在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----';//一段隨機(jī)字符串,最好根據(jù)時(shí)間來生成,為了分割多個(gè)表單項(xiàng)
13 // 模擬一個(gè)文件提交請求
14 xhr.setRequestHeader("Content-Type", "multipart/form-data, boundary="+boundary);
15 //xhr.setRequestHeader("Content-Length", file.size); 在chrome下會(huì)出錯(cuò),可能是出于安全考慮,不允許這樣做
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直接用的原文件名稱,并沒有改名,這在原名為漢字的情況下會(huì)提示錯(cuò)誤,應(yīng)該處理一下,但不知道怎么弄
| 值 | 描述 |
|---|---|
| application/x-www-form-urlencoded | 在發(fā)送前編碼所有字符(默認(rèn)) |
| multipart/form-data |
不對字符編碼。 在使用包含文件上傳控件的表單時(shí),必須使用該值。 |
| text/plain | 空格轉(zhuǎn)換為 "+" 加號,但不對特殊字符編碼。 |
上面是在w3cschool搜到的,既然multipart/form-data不對字符編碼,但為什么會(huì)出錯(cuò),希望知道的能告訴一聲
模擬出來的數(shù)據(jù)要以二進(jìn)制發(fā)送。火狐XMLHttpRequest 對象中有sendAsBinary()方法,這個(gè)是火狐私有的。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 }
服務(wù)端接收文件時(shí)和普通上傳文件時(shí)一樣
例如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.顯示上傳進(jìn)度
1 var xhr = new XMLHttpRequest();
2 upload =xhr.upload;
3 upload.addEventListener("progress", updateProgress, false);//updateProgress 處理上傳進(jìn)度
4 xhr.open('post', “服務(wù)端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 }
這個(gè)也挺簡單,代碼如上,不過要注意的是:
1.事件要綁定到 XMLHttpRequest的 upload上,這樣才能監(jiān)聽上傳進(jìn)度。 XMLHttpRequest上同時(shí)也有progress事件,不過是監(jiān)聽下載的。
2. 火狐和chrome調(diào)用updateProgress頻率好像一樣,具體是每秒調(diào)用一次還是怎么著,我也不是很清楚。假如文件很小,而且網(wǎng)絡(luò)很快(本地測試的,當(dāng)然快)FF就不會(huì)觸發(fā)progress事件。
在火狐下, 在上傳完成時(shí)也不觸發(fā)事件所以總是導(dǎo)致進(jìn)度到不了100%,到了百分之80,90就不動(dòng)了。
好了,功能基本都實(shí)現(xiàn)了,另外上面那些代碼都是我在寫篇文章是復(fù)制過來的(寫了將近一個(gè)星期的時(shí)間,有空就寫,程序基本功能完成是在兩個(gè)星期前。)。
最后在附上一個(gè)我搜索資料過程中找到的一個(gè)jquery 插件 jquery-filedrop。
浙公網(wǎng)安備 33010602011771號