JavaScript對於Web上傳的總結

前言

HTML5中提供的文件API在前端中有著豐富的應用,上傳、下載、讀取內容等在日常的交互中很常見。而且在各個瀏覽器的兼容也比較好,包括移動端,除瞭IE隻支持IE10以上的版本。想要更好地掌握好操作文件的功能,先要熟悉每個API。

1. FileList 對象和 file 對象

  HTML5中的 input[type="file"] 標簽有個 multiple 屬性,允許用戶選擇多個文件,FileList對象則就是表示用戶選擇的文件列表。這個列表中的每一個文件,就是一個file對象。

HTML5也添加瞭文件對象(File),可以方便的獲得文件本身的一些信息(name、size、type),在上傳前知道文件的大小,實現限制上傳大小。

<input type="file" id="files" multiple accept="image/gif,image/jpeg,image/jpg,image/png">  // accept 屬性,可以用來規定能夠通過文件上傳進行提交的文件類型。
<script>
    var elem = document.getElementById('files');
    elem.onchange = function (event) {
        var files = event.target.files;
        for (var i = 0; i < files.length; i++) {
            console.log(files[i].name);            
        }
    }
</script>

2. Blob 對象

Blob 對象相當於一個容器,可以用於存放二進制數據。它有兩個屬性,size 屬性表示字節長度,type 屬性表示 MIME 類型。

一個Blob對象就是一個包含有隻讀原始數據的類文件對象。Blob對象中的數據並不一定得是JavaScript中的原生形式。File接口基於Blob,繼承瞭Blob的功能,並且擴展支持瞭用戶計算機上的本地文件。

如何創建

1)Blob 對象可以使用 Blob() 構造函數來創建。

var blob = new Blob(['hello'], {type:"text/plain"});

Blob 構造函數中的第一個參數是一個數組,存放數據可以是任意多個ArrayBuffer、ArrayBufferView、Blob或者 DOMString對象。

1、創建一個裝填DOMString對象的Blob對象
var s = "

Hello World!

"; var blob = new Blob([s],{type:"text/xml"});

2、創建一個裝填ArrayBuffer對象的Blob對象
var abf = new ArrayBuffer(8);
var blob = new Blob([abf],{type:"text/plain"});
3、創建一個裝填ArrayBufferView對象的Blob對象
var abf = new ArrayBuffer(8);
var abv = Int16Array(abf);
var blob = new Blog(abv,{type:"text/plain"});

2)Blob 對象可以通過 slice() 方法來返回一個新的 Blob 對象。

var newblob = blob.slice(0,5, {type:"text/plain"});

slice() 方法使用三個參數,均為可選。第一個參數代表要從Blob對象中的二進制數據的起始位置開始復制,第二個參數代表復制的結束位置,第三個參數為 Blob 對象的 MIME 類型。

3)canvas.toBlob() 也可以創建 Blob 對象。toBlob() 使用三個參數,第一個為回調函數,第二個為圖片類型,默認為 image/png,第三個為圖片質量,值在0到1之間。

var canvas = document.getElementById('canvas');
canvas.toBlob(function(blob){ console.log(blob); }, "image/jpeg", 0.5);

下載文件

Blod 對象可以通過 window.URL 對象生成一個網絡地址,結合 a 標簽的 download 屬性來實現下載文件功能。

比如把 canvas 下載為一個圖片文件。

createDownload("download.txt","download file");

function createDownload(fileName, content){
    var blob = new Blob([content]);
    var link = document.createElement("a");
    link.innerHTML = fileName;
    link.download = fileName;
    link.href = URL.createObjectURL(blob);
    document.getElementsByTagName("body")[0].appendChild(link);
}

執行後頁面上會生成此Blob對象的地址,點擊後可下載。

3. FileReader 對象

FileReader 對象主要用來把文件讀入內存,並且讀取文件中的數據。通過構造函數創建一個 FileReader 對象

var reader = new FileReader();

該對象有以下方法:

abort:中斷讀取操作。 readAsArrayBuffer:讀取文件內容到ArrayBuffer對象中。 readAsBinaryString:將文件讀取為二進制數據。 readAsDataURL:將文件讀取為data: URL格式的字符串。 readAsText:將文件讀取為文本。

上傳圖片預覽

在常見的應用就是在客戶端上傳圖片之後通過 readAsDataURL() 來顯示圖片。

<input type="file" id="files" accept="image/jpeg,image/jpg,image/png">
<img src="blank.gif" id="preview">
<script>
    var elem = document.getElementById('files'),
        img = document.getElementById('preview');
    elem.onchange = function () {
        var files = elem.files,
            reader = new FileReader();
        if(files && files[0]){
            reader.onload = function (ev) {
                img.src = ev.target.result;
            }
            reader.readAsDataURL(files[0]);
        }
    }
</script>

數據備份與恢復

FileReader 對象的 readAsText() 可以讀取文件的文本,結合 Blob 對象下載文件的功能,那就可以實現將數據導出文件備份到本地,當數據要恢復時,通過 input 把備份文件上傳,使用 readAsText() 讀取文本,恢復數據。

4. WebSocket上傳

var url = "ws://localhost:8081/upload";
var ws = new WebSocket(url);
ws.binaryType = 'arraybuffer';
ws.onopen = function () {
    window.console.log('websocket connection success ...');
};

//...
ws.onerror = function (error) {
  window.console.log('WebSocket Error ' + error);
};

//...
function uploadFile(file){
   //實例化FileReader對象
   var fr = new FileReader();
   //定義文件加載完的監聽事件,執行回調函數 
   fr.addEventListener("loadend", function() {
      ws.send(fr.result);
   });
   //把文件加載進ArrayBuffer中
   fr.readAsArrayBuffer(file);
}

實際使用中,瀏覽器websocket用做上傳較少

websocket上傳存在幾個問題:

一般對於現有的上傳服務,服務端需要單獨開發接口 同樣無法獲得上傳的進度信息(變通方式:必須使用分片來模擬進度)

5. XHR2 上傳

XHR即我們常說的ajax(Asynchronous JavaScript and XML)

XHR的特點:

可以設置HTTP請求的時限。 可以獲取服務器端的(或向服務端發送)二進制數據。 可以使用FormData對象管理表單數據。 可以上傳文件。xhr.upload(upload = XMLHttpRequestUpload) 可以獲得數據傳輸的進度信息, xhr.upload.onprogess。 可以請求不同域名下的數據(跨域請求)。

function uploadFile(file){
   var xhr = new XMLHttpRequest();
   xhr.open('POST','/upload',true);
   var formData = new FormData();
   xhr.upload.onprogress = function(data){
      var per = Math.ceil((data.loaded/data.total)*100);
      //$('#'+file.uid+' .progress-bar').css('width',per+'%');
   }
   xhr.onreadystatechange = function() {
       if (xhr.readyState == 4 && xhr.status == 200) {
         // Every thing ok, file uploaded
           var res = JSON.parse(xhr.responseText);
           if(res.code ==200){
               // upload success
           }
       }
   };
   formData.append("upload_file", file);
   formData.append("filename",file.name);
   xhr.send(formData);
}

xhr2在結合H5的其他特性,可以實現上述flash上傳的所以功能外,還可以實現拖拽上傳功能。

由於諸多HTML5特性(Blob ,xhr2,FileReader,ArrayBuffer等)在IE10+中才有效,

所以xhr2上傳更適合在chrome,firefox等高版本的瀏覽器或和移動端使用。

You May Also Like