JavaScript怎么上傳圖片


在XMLHttpRequest Level2出台之前,大多數的異步上傳圖片都是利用iframe去實現的。

至於具體的實現細節,我就不在這邊啰嗦的,Google一下就有文章談這個東西。

這次主要說說,怎么用新的API去實現圖片上傳。

 

首先,少不了的自然是XMLHttpRequest Level2的一些新特性啦。

其中最為實在的就是FormData對象,直接把表單(form)的DOM對象轉為FormData對象,然后向服務器發送。

還有就是Progress事件的支持,異步上傳終於可以查看進度條啦!

這里我就不廢話了,因為大多數人應該都看過的 阮一峰 的 《XMLHttpRequest Level 2 使用指南》,直接貼代碼吧。

1 var formData= new FormData(form),
2     xhr= new XMLHttpRequest();
3 
4 xhr.open("POST", url);
5 xhr.send(formData);    

接口的部分也很簡單,例如PHP,直接用$_POST、$_FILES就可以拿到相關的數據.

沒錯,就是這么簡單。

而通過監聽Progress時間,就可以判斷當前數據上傳/下載的進度。

1 xhr.upload.onprogress = function (e) {
2     console.log(e.loaded / e.total * 100);    // 上傳進度
3 }
4 
5 xhr.onprogress = function (e) {
6     console.log(e.loaded / e.total * 100);    //  下載進度
7 }

至於XMLHttpRequest Level2的支持情況,在移動端還是比較理想的。

 

 

一直以來,無數的前端屌絲都渴望瀏覽器可以提供JavaScript訪問本地文件的API。

其實大老早,IE就能利用ActiveX來操作本地文件了,但因為並非W3C的標准,一直就只有IE在玩。

於25 October 2012,W3C訂立了File API的草案。

另外,和File對象配套使用的,還有FileReader對象。具體有什么用后面再說。

下面是它們倆的支持度,情況比較一般。不過先學着就差不多了,哈~

 

先說說File對象吧。

File對象是來自用戶在一個<input>元素上選擇文件后返回的FileList對象,也可以是來自由拖放操作生成的 DataTransfer對象.

如下:

1 // input:file的File對象
2 document.querySelector("input[type=file]").files;    // return FileList
3 
4 // drop事件的File對象
5 elem.ondrop = function (e) {
6     e.preventDefault();
7     return e.dataTransfer.files;     // return FileList
8 };

都是以一個FileList的對象返回。這個FileList的對象類似於NodeList。有length屬性,但並非數組。

下面是Chrome Console打印出來的FileList對象:

再看看File對象有什么屬性:

那些屬性都代表什么意思我就不再廢話了。但我們可以留意到,File對象是繼承於Blob對象,至於什么是Blob對象,后面的篇幅咱們再提及。

 

一開始,我們還提到一個FileReader的對象,說是配套着File對象一起用。

使用FileReader對象,web應用程序可以異步的讀取存儲在用戶計算機上的文件(或者原始數據緩沖)內容,可以使用File對象或者Blob對象來指定所要讀取的文件或數據.

具體怎么用,我們看看下面的代碼:

 1 // 創建一個FileReader對象
 2 var reader = new FileReader();
 3 
 4 // 綁定load事件
 5 reader.onload = function(e) {
 6     console.log(e.target.result);
 7 }
 8 
 9 // 讀取File對象的數據
10 reader.readAsDataURL(document.querySelector("input[type=file]").files[0]);

當FileReader對象通過readAsDataURL讀取數據成功后,就會觸發load事件。target中的result屬性的值,就是該文件的base64數據

 

當然,FileReader對象不單單只有readAsDataURL一個方法。

 1 /**
 2  * 中止該讀取操作.在返回時,readyState屬性的值為DONE.
 3  */
 4 reader.abort();
 5 
 6 
 7 /**
 8  * 開始讀取指定的Blob對象或File對象中的內容. 
 9  * 當讀取操作完成時,readyState屬性的值會成為DONE,如果設置了onloadend事件處理程序,則調用之.
10  * 同時,result屬性中將包含一個data: URL格式的字符串以表示所讀取文件的內容.
11  */
12 reader.readAsDataURL(file);
13 
14 
15 /**
16  * 同上, result屬性中將包含一個字符串以表示所讀取的文件內容.
17  * encoding是可選項,類型為字符串,表示了返回數據所使用的編碼.如果不指定,默認為UTF-8.
18  */
19 reader.readAsText(file[, encoding ]);
20 
21 
22 /**
23  * 同上, result屬性中將包含一個ArrayBuffer對象以表示所讀取文件的內容.
24  */
25 reader.readAsArrayBuffer(file); 
26 
27 
28 /**
29  * 同上, result屬性中將包含所讀取文件的原始二進制數據.
30  */
31 reader.readAsBinaryString(file);

 

既然拿到了文件的base64,那做事情就方便多了。

例如,我們可以直接把base64的字符串post到服務器端。

 1 var reader = new FileReader();
 2 
 3 reader.onload = function(e) {
 4     var xhr = new XMLHttpRequest(),
 5         fromData = new FormData();
 6 
 7     fromData.append("base64", e.target.result);
 8     xhr.open("post",url, true);
 9     xhr.send(fromData);
10 }
11 
12 reader.readAsDataURL(document.querySelector("input[type=file]").files[0]);

是不是覺得有什么不對?

既然都用FormData了,還轉個毛線base64啊!

 

轉成base64之后,最大的好處就是可以繪制到Canvas上,然后對圖片進行編輯!

在客戶端這邊做裁剪啊塗鴉啊什么的,編輯完成后再利用Canvas對象的toDataURL方法,就可以輸出編輯后圖片的base64數據。

細節的實現我這里就不說了。

 

我們再看看HTML5的file表單元素提供了什么新的支持:

1 <input type="file" accept="image/*" id="file_image" name="file_image" multiple />
2 <input type="file" accept="video/*" id="file_video" name="file_video" />

accept屬性,可以用來限制用戶上傳文件的類型。這個屬性IOS和OSX支持得很好。

另外還有multiple屬性,意思就是可以選擇多個文件。添加了這個屬性之后,再配合FormData對象,可以實現批量上傳。

 1 (function (W, D) {
 2     var fileForm = document.getElementById("file_form"),
 3         fileImage = document.getElementById("file_image");
 4 
 5     function testAjax(files, i) {
 6         if (i < 0) {
 7             return ;
 8         }
 9 
10         var xhr = new XMLHttpRequest(),
11             data = new FormData();
12 
13         xhr.onload = function () {
14             // 遞歸
15             testAjax(files, --i);
16         };
17         data.append("file_image", files[i]);
18         xhr.open("post", "test/demo2.php", true);
19         xhr.send(data);
20     }
21 
22     fileForm.addEventListener("submit", function (e) {
23         e.preventDefault();
24         var files = fileImage.files;
25 
26         testAjax(files, --files.length);
27     }, false);
28 
29 })(window, document);

 

好了,寫到這里就差不多了。

額...

是不是忘記什么了?

哦!Blob對象!

它嘛,就是一個二進制數據的對象。這個玩意就有空再說了,想了解的童鞋自己去看文檔吧。

 

 

最后,吐槽一下。

經測試,MIUI V4 & MIUI V5 的自帶瀏覽器(原生?),FileReader對象中base64數據的結構出錯,缺少了圖像類型的數據。

正確的base64格式:data:image/jpeg;base64,iVBO…AL5wF1K4MqU0AAAAASUVORK5CYII=

MIUI自帶瀏覽器的格式:data:base64,iVBO…AL5wF1K4MqU0AAAAASUVORK5CYII=

 

 

 

參考資料:

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input

https://developer.mozilla.org/zh-CN/docs/DOM/File

https://developer.mozilla.org/zh-CN/docs/DOM/XMLHttpRequest/FormData

https://developer.mozilla.org/es/docs/XMLHttpRequest/Usar_XMLHttpRequest

http://caniuse.com/#feat=xhr2

http://caniuse.com/#feat=fileapi

http://caniuse.com/#feat=filereader

 

 

本文作者:Maple Jan

本文鏈接:http://www.cnblogs.com/maplejan/p/3297699.html

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM