在 HTML5 File API 出現以前,前端對於文件的操做是很是有侷限性的,大多須要配合後端實現。出於安全角度考慮,從本地上傳文件時,代碼不可能獲取文件在用戶本地的地址,因此純前端不可能完成一些相似圖片預覽的功能。可是 File API 的出現,讓這一切變成了可能。前端
一、FileList 對象canvas
FileList 對象針對表單的 file 控件。當用戶經過 file 控件選取文件後,這個控件的 files 屬性值就是 FileList 對象。它在結構上相似於數組,包含用戶選取的多個文件。若是 file 控件沒有設置 multiple 屬性,那麼用戶只能選擇一個文件,FileList 對象也就只有一個元素了。後端
好比我選擇了兩個文件,控制檯打印:數組
FileList {0: File, 1: File, length: 2} 0: File 1: File length:2 __proto__: Object
通常來講,咱們不可能手動構造 FileList 對象,只能被動地讀取,也就是說只有用戶主動觸發了文件讀取行爲,js 才能訪問到 FileList,而這一般發生在表單選擇文件或者拖拽文件中。緩存
二、File對象安全
一個 FileList 對象包含了咱們選中的 File 對象,那麼一個 File 又有哪些屬性呢?異步
咱們能夠選一個文件,本身打印出來看看。函數
三、Blobthis
File 對象是繼承自 Blob 對象的,Blob 又是什麼鬼?編碼
Blob(Binary Large Object)對象表明了一段二進制數據,提供了一系列操做接口。其餘操做二進制數據的 API(好比 File 對象),都是創建在 Blob 對象基礎上的,繼承了它的屬性和方法。
生成 Blob 對象有兩種方法:一種是使用 Blob 構造函數,另外一種是對現有的 Blob 對象使用 slice 方法切出一部分。
(1)Blob 構造函數,接受兩個參數。第一個參數是一個包含實際數據的數組,第二個參數是數據的類型,這兩個參數都不是必需的。
(2)Blob 對象的 slice 方法,將二進制數據按照字節分塊,返回一個新的 Blob 對象。
var a = ["hello", "world"]; var myBlob = new Blob(a, { "type" : "text/xml" }); var newBlob = myBlob.slice(0, 5); console.log(newBlob);
Blob 對象有兩個只讀屬性:
四、FileReader
FileReader API 纔是咱們接下去完成一些任務的關鍵。FileReader API 用於讀取文件,即把文件內容讀入內存。它的參數是 File 對象或 Blob 對象。
對於不一樣類型的文件,FileReader 提供不一樣的方法讀取文件。
除了以上三種不一樣的讀取文件方法,FileReader API 還有一個 abort 方法,用於停止文件上傳。
var reader = new FileReader(); reader.abort();
FileReader 對象採用異步方式讀取文件,能夠爲一系列事件指定回調函數。
獲取到了文件的 base64 編碼,作一些諸如圖片預覽的功能,也就手到擒來了,有興趣的能夠本身嘗試下,相似的還有文字預覽啊,等等。
五、URL
還有個強大的東西——URL 對象!
調用 URL 對象的 createObjectURL 方法,傳入一個 File 對象或者 Blob 對象,能生成一個連接。
var objecturl = window.URL.createObjectURL(blob);
上面的代碼會對二進制數據生成一個 URL,這個 URL 能夠放置於任何一般能夠放置 URL 的地方,好比 img 標籤的 src 屬性。須要注意的是,即便是一樣的二進制數據,每調用一次 URL.createObjectURL 方法,就會獲得一個不同的 URL。這個 URL 的存在時間,等同於網頁的存在時間,一旦網頁刷新或卸載,這個 URL 就失效。(File 和 Blob 又未嘗不是這樣呢)除此以外,也能夠手動調用 URL.revokeObjectURL 方法,使 URL 失效。
對於 File 或者 Blob 對象,咱們能夠這樣理解,它們的存在,依賴於頁面,而 URL 能給這些 "轉瞬即逝" 的二進制對象一個臨時的指向地址。這個臨時的地址還有什麼用呢?也能作圖片預覽,相比前面用 readAsDataURL 的實現,更簡單了。
<input type='file' multiple /><br/>
<img />
<script> document.querySelector("input").onchange = function() { var files = this.files; document.querySelector("img").src = window.URL.createObjectURL(files[0]); } </script>
六、Canvas & dataURL & Blob
canvas 中有 toDataURL 函數,能夠將 canvas 轉爲 dataURL 形式的 base64 編碼,而 Blob 也能夠轉爲 dataURL,這三者之間是否能夠互相轉換?有沒有什麼實用之處?
(1)canvas -> dataURL
用 toDataURL 方法,比較簡單,很少說。
(2)blob -> dataURL
用 FileReader 的 readAsDataURL 方法
(3)dataURL -> blob
這個函數有點屌
function dataURLtoBlob(dataurl) { var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); while(n--){ u8arr[n] = bstr.charCodeAt(n); } return new Blob([u8arr], {type:mime}); }
(4)dataURL - canvas
將 image 的 src 屬性置爲 dataURL,再用 drawImage 方法畫上去。
(5)blob - canvas
如何把二進制形式的圖片畫上 canvas?先用 readAsDataURL 轉爲 dataURL,接着就是 (4) 的事情了。
(6)canvas - blob
canvas 有原生的 toBlob 方法,使得圖片文件能夠被緩存或保存到本地
canvas 轉爲 blob 也能夠用 dataURL 作跳板,先將 canvas 轉爲 dataURL(1),再用 dataURL 轉爲 blob(3)。
利用它們之間的轉換能夠作些什麼好玩的事呢?好比能夠上傳圖片,對圖片作各類處理,而後保存等。