上傳我們一般都是用“input[type=file]”控件。當你用此控件時,你就授權了網頁和服務器訪問對應的文件,就可以得到File對象。
友情提示在,在Android手機webview中,是不支持上傳文件的,網上說是修改Android端的代碼,但我沒試過,我們這邊是使用客戶端提供的接口來實現上傳的。
下面的示例代碼可以在這里查看到。
一、accept屬性
該屬性表明了服務器端可接受的文件類型,可以限制你手機選擇相關的文件,如果限制多個,可以用逗號分割,下面的代碼就表示只能選擇圖片與音頻相關的文件:
<input accept="image/*,audio/*" type="file"/>
在移動端,點擊后會讓你選擇拍照或相冊,還是蠻高大上的。下圖是UC瀏覽器中:
二、change事件
一般選擇文件都會使用“change”事件,下面的代碼就是綁定了change事件,彈出文件大小:
var upload = document.getElementById('upload'); upload.addEventListener('change', function() { var file = upload.files[0]; alert(file.size); }, false);
1) 有些手機瀏覽器在點擊的時候,會彈出鍵盤選擇,我用onfocus="this.blur()",來強制失去焦點。
<input type="file" id="upload" onfocus="this.blur()"/>
2) 當選擇過一次后,再次選擇同一個文件,“change”事件不會觸發,因為value沒有改變,在網上看到個方法,我還沒有在實際項目中使用,兼容性有待考證。
使用“Node.cloneNode”復制上傳元素,再用“Node.replaceChild”替換節點。
這里注意下:克隆一個元素節點會拷貝它所有的屬性以及屬性值,但不會拷貝那些使用addEventListener()方法或者node.onclick = fn用JavaScript動態綁定的事件。
upload.addEventListener('change', function() { var upload = document.getElementById('upload'); //每次要動態獲取 var file = upload.files[0]; console.log(file.size); //解決上傳相同文件不觸發onchange事件 var clone = upload.cloneNode(true); clone.onchange = arguments.callee; //克隆不會復制動態綁定事件 clone.value = ''; upload.parentNode.replaceChild(clone, upload); }, false);
三、File對象
用戶所選擇的文件都存儲在了一個FileList對象上,其中每個文件都對應了一個File對象
File對象負責處理那些以文件形式存在的二進制數據,也就是操作本地文件。
File對象是Blob【下面會提到】的特殊類型,即大塊的二進制數據,File對象的尺寸及類型等屬性都繼承自Blob。
1)File對象可以通過3種方式獲取:
1. <input>元素上選擇文件后返回的FileList對象中的成員
2. 拖放操作【Drag或Drop】生成的 DataTransfer對象內files屬性中的成員
3. HTMLCanvasElement上執行mozGetAsFile()方法后的返回結果
document.getElementById('upload').files[0]//選取第一個文件對象
2)File對象有9個屬性,這里就只介紹3個:
1. name:當前File對象所引用文件的文件名,不包括路徑,只讀。
2. size:文件大小,單位為字節,只讀的64位整數.
3. type:MIME類型,只讀字符串,如果類型未知,則返回null。有些移動端的瀏覽器明明選擇了圖片,返回的卻是null,非常坑。
還有3個非標准的方法:getAsBinary()、getAsDataURL()和getAsText(in DOMString encoding)。
這3個方法現在已經過時,現在用FileReader對象中的方法來取代。
四、FileReader
web應用程序可以異步的讀取存儲在用戶計算機上的文件(或者原始數據緩沖)內容,可以使用File對象或者Blob對象來指定所要處理的文件或數據。
1) readAsArrayBuffer():在返回的result屬性中將包含一個ArrayBuffer對象【緩沖數組,是一種用於呈現通用、固定長度的二進制數據的類型】以表示所讀取文件的內容
Blob可以“append”,ArrayBuffer數據。ArrayBuffer存在的意義就是作為數據源提前寫入在內存中,就是提前釘死在某個區域,長度也固定。
2) readAsBinaryString():result屬性中將包含所讀取文件的原始二進制數據
3) readAsDataURL():result屬性中將包含一個data: URL格式的字符串以表示所讀取文件的內容
4) readAsText():result屬性中將包含一個字符串以表示所讀取的文件內容
下面的代碼是獲取data:URL,可以將返回的result內容賦值給img的src,用於預覽等操作。
var reader = new FileReader(); reader.readAsDataURL(file); reader.onload = function(e) { var img = new Image(); img.src = this.result; console.log(this.result); };
console.log(this.result)內容如下:
五、URL對象
URL對象是硬盤上指向文件的URL。上面的例子中獲取圖片的引用,通過讀取data URI,data URI是個一大串的字符。
圖片原本就在硬盤上,還要轉換成另一個格式再用,有點繞了,完全可以直接引用文件的URL,下面是兩個方法:
1) URL.createObjectURL():接收一個文件的引用(File或Blob對象)返回一個URL對象
2) URL.revokeObjectURL():銷毀創建的URL
var url = URL.createObjectURL(file); var img = new Image(); img.src = url; img.onload = function(e) { window.URL.revokeObjectURL(this.src); //銷毀 } console.log(url);
console.log(url)內容如下:
在移動端需要做個兼容性判斷:
window.URL = window.URL || window.webkitURL;
六、Blob對象
Blob(binary large object)對象代表了一段二進制數據,就是一個包含只讀原始數據的類文件對象。
File接口基於Blob,繼承了Blob的功能,並且擴展支持了用戶計算機上的本地文件。
1)創建Blob對象的4種方法:
1. 調用Blob構造函數
2. 使用一個已有Blob對象上的slice()方法切出另一個Blob對象
3. 調用canvas對象上的toBlob方法
4. 過氣的方法,通過BlobBuilder接口創建,但兼容性不好,並且現有的BlobBuilder實現都是帶前綴的
2)利用Blob對象,生成可下載文件
var blob = new Blob(["pwstrick"]);//數組中添加DOMString對象 var a = document.createElement("a"); a.href = URL.createObjectURL(blob);//創建URL對象 a.download = "test.txt";//HTML5新屬性 a.textContent = "test"; document.getElementsByTagName('body')[0].appendChild(a);
生成一個“a”標簽,並且點擊這個鏈接,可以下載一個txt文本,內容是“pwstrick”。
3)通過slice方法,將二進制數據按照字節分塊,返回一個新的Blob對象
upload.addEventListener('change', function() { var upload = document.getElementById('upload'); //每次要動態獲取 var file = upload.files[0]; var start = 0; var chunk = 1024 * 10; //10KB var end = start + chunk; var size = file.size; while (start < size) { segment(file, start, end); start = end; end = start + chunk; if (end > size) { end = size; } } }, false); function segment(file, start, end) { var reader = new FileReader(); reader.onload = function(evt) { console.log(['Read bytes: ', start, ' - ', end].join('')); }; var blob = file.slice(start, end); reader.readAsBinaryString(blob); }
七、formData
XMLHttpRequest Level 2添加了一個新的接口FormData。
利用FormData對象,可以使用鍵值對來模擬一個完整的表單,然后使用XMLHttpRequest發送這個"表單"。
使用FormData的最大優點就是我們可以異步上傳一個二進制文件。
var formData = new FormData(); formData.append("name", "value");//普通鍵值對 formData.append("blob", blob); //傳遞一個blob對象 formData.append("file", file); //傳遞一個file對象 var oReq = new XMLHttpRequest(); oReq.open("POST", "http://xx.com"); oReq.send(formData);
參考資料:
https://developer.mozilla.org/zh-CN/docs/Using_files_from_web_applications 在web應用中使用文件
http://javascript.ruanyifeng.com/htmlapi/file.html 文件和二進制數據的操作
http://www.iunbug.com/archives/2012/06/04/208.html [譯]JavaScript文件操作基礎
http://www.iunbug.com/archives/2012/06/05/254.html [譯]JavaScript文件操作URL對象
http://www.html5rocks.com/zh/tutorials/file/dndfiles/ 通過 File API 使用 JavaScript 讀取文件