不少時候咱們都會有圖片上傳的功能需求,若是咱們先將圖片上傳到服務器,而後在將返回結果顯示在前端,這樣的操做性能開銷太大,若是圖片一多,簡直要哭,並且萬一還碰到了上傳錯誤要刪除的,那簡直沒法想象了。因此咱們須要先將圖片在前端展現後,而後由用戶確認沒有問題了,再統一上傳,這樣纔是比較理想的。css
input
type=file
相信你們都知道,要在前端實現圖片的上傳,咱們離不開的是一個 <input>
type=file 的 input 元素,該元素能夠容許用戶選擇一個或者多個文件。html
<input type="file">
複製代碼
此時,咱們點擊 input 元素,就能夠瀏覽本地文件並選擇上傳。可是,此時咱們只能選擇一個文件,而不能多個。這時就須要 <input>
標籤的另外一個屬性 multiple
前端
multiple
multipla
屬性容許用戶選擇多個文件,他是一個不須要值的屬性,也就是說,只要你的 input
標籤上出現了這個屬性,那麼不論其值是什麼,他都會支持多文件選擇。一般來講咱們使用 multiple 只會使用其屬性名,而不會給他加值web
<input type='file' multiple>
複製代碼
accept
若是你嘗試了以上標籤及屬性,你會發現你的不但能選擇 image 文件,還能選擇其餘各類各樣的文件。可是通常來講對咱們有須要的只是 image 文件,至於其餘什麼的,愛咋咋地吧,只要不出來妨礙我就能夠了。因此這時候咱們須要 accept 的屬性來進行限制。accept 屬性接受逗號分隔的 MIME 類型字符串:數組
1. accept='image/png' 或者 accept='.png' --只接受 .png 格式的圖片
2. accept='iamge/png,image/jpeg' 或者 accept='.png, .jpg .jpeg' 接受 .png .jpeg .jpg 格式的圖片
3. accept='image/*' 接受全部類型的 image
<input type='file' multiple accetp='image/*'>
複製代碼
注: 'image/*' 在部分瀏覽器中(Chrome和Safari等Webkit瀏覽器)響應比較緩慢,能夠用如下方法代替瀏覽器
<<input type="file" multiple accept='image/png, image/jpeg, image/jpg, image/svg, image/gif'>
複製代碼
樣式
通常來講咱們都會將 input 設置爲 display:none
, 而後經過 label 來設置其顯示樣式服務器
// css
input{
display:none;
}
label{
// 關於label樣式
}
// html
<input type='file' multiple accept='image/png, image/jpeg, image/jpg, image/svg, image/gif' id='inputFile'>
<label for="inputFile">上傳圖片</label>
複製代碼
FileList 對象
選中文件經過 HTMLInputElement.files 屬性返回了一個 FileList 對象,這個對象是一個包含了許多 file 文件的列表。每一個 file 對象包含了一下信息:app
1. name:文件名
2. lastModified:文件最後一次修改時間(時間戳形式)
3. lastModifiedDate:文件最後一次修改時間(UNIX timestamp形式)
4. size: 文件大小(byte 爲單位)
5. type:文件 MIME 類型
複製代碼
咱們能夠經過對 input 標籤監聽 change 事件:異步
// js
document.getElementById('inputFile').addEventListener('change', changeHandler, false);
function changeHandler(e) {
var files = e.target.files;
console.log(files) // 這裏咱們能獲取到所選擇的文件信息,須要注意的一點是 files 是個類數組對象。
}
複製代碼
FileReader or 對象 URL
當咱們獲取到文件對象信息 files 了之後,咱們要如何將他在頁面上預覽出來,這裏提供了兩種方法:FileReader 或者 對象 URL。
這兩種方法該如何使用,又有何區別呢?svg
1. FileReader
FileReader 實現了一種異步的讀取機制。他必須先經過 FileReader()
構造函數建立出一個 fileReader 實例。該實例實現了一下幾個方法和事件(部分):
-
readerAsDataURL(file): 讀取文件並以數據 URI 形式保存在 result 屬性中
-
load 事件:在文件加載成功後觸發 load 事件
-
error 事件:在文件加載失敗後觸發 error 事件
-
progress 事件:在讀取文件的過程當中觸發 progress 事件,該事件能夠近似(間隔性觸發,不是實時響應)監聽文件上傳進度。該方法有三個屬性:lengthComputable(進度信息是否可用), loaded(已經加載了多少), total總共有多少。
usage:
files.forEach(function(item) {
var reader = new FileReader();
reader.readAsDataURL(item);
reader.onprogress = function(e) {
if (e.lengthComputable) {
// 簡單把進度信息打印到控制檯吧
console.log(e.loaded / e.total + '%')
}
}
reader.onload = function(e) {
var image = new Image()
image.src = e.target.result
body.appendChild(image)
}
reader.onerror = function(e) {
console.log('there is an error!')
}
})
複製代碼
2. 對象 URL
對象 URL 指的是引用保存在 File 或 Blob 中的數據 URL。使用對象 URL 的時候不用像 FIleReader 同樣要先把數據讀取到 JavaScript 中,他能夠引用 內存中 URL 地址而使用。
建立對象 URL 方法: window.URL.createObjectURL()。兼容寫法:
function creatObjectURL(file) {
if (window.URL) {
return window.URL.createObjectURL(file);
} else if (window.webkitURL) {
return window.webkitURL.createObjectURL(file);
} else {
return null
}
}
複製代碼
usage:
files.forEach(function(item) {
var url = createObjectURL(item)
var image = new Image()
image.src = url
body.appendChild(image)
})
複製代碼
區別:
-
FileReader 是異步操做,而對象 URL 是同步操做
-
FileReader.readAsDataURL 返回的是一個包含更多字節的
base64
格式,createObejctURL 返回的是一個帶 hash 的 URL。 -
因爲二者返回形式不一樣,FileReader.readerAsDataURL 會佔用更多內存,可是當你再也不使用他的時候,他會自動釋放內存,而 createObjectURL 則只有當你的頁面關閉或者手動調用 revokeObejctURL 的時候才能釋放內存。
-
從兼容性來講: createObjectURL 和 FileReader.readerAsDataURL 都兼容 IE10+ 和現代全部主流瀏覽器
-
createObjectURL 相對 FileReader.readerAsDataURL,效率較高。可是若是圖片較多,則最好手動清除內存,能夠把 URL 當作參數直接傳給 window.URL.revokeObjectURL()。兼容寫法:
function revokeObjectURL(url) { if (widnow.URL) { return window.URL.revokeObjectURL(url) } else { return window.webkitURL.revokeObjectURL(url) } } 複製代碼
簡單實現:
// css input{ display:none; } label{ // 關於label樣式 } // html <input type='file' multiple accept='image/png, image/jpeg, image/jpg, image/svg, image/gif' id='inputFile'> <label for="inputFile">上傳圖片</label> // js var inputFile = document.getElementById('inputFile') var body = document.body || document.getElementsByTagName('body')[0] inputFile.addEventListener('change', changeHandler, false) function changeHandler(e) { var files = Array.from(e.target.files) files.forEach(function(item) { var image = new Image() image.src = createObjectURL(item) body.appendChild(image) image.onload = function() { revokeObjectURL(this.src) } }) } function createObjectURL(file) { if (window.URL) { return window.URL.createObjectURL(file) } else { return window.webkitURL.createObjectURL(file) } } function revokeObjectURL(file) { if (window.URL) { return window.URL.revokeObjectURL(file) } else { return window.webkitURL.revokeObjectURL(file) } } } else { 前端學習培訓、視頻教程、學習路線,添加威信 kaixin666haoyun 與我聯繫 }