在前端開發中,拖拽上傳文件是一種很常見的需求。經過拖拽來實現文件上傳須要瞭解FileReader
這個File API
以及對應的拖拽事件前端
咱們先了解一下,在前端表單中是如何處理文件上傳的瀏覽器
一直以來,咱們都經過<input type='file'>
字段來獲取文件的對應信息。HTML5爲文件輸入元素添加了一個files
集合,在files
集合中,有一組File
對象,每一個File
對象對應着一個文件bash
File
對象屬性(只讀屬性):服務器
屬性 | 類型 | 描述 |
---|---|---|
name | 字符串 | 本地文件系統中的文件名 |
size | 數字 | 文件的字節大小 |
type | 字符串 | 文件的MIME類型 |
lastModifiedDate | 字符串 | 文件上一次被修改的時間 |
具體的實現代碼以下:app
<input type='file' id='files'>
<script>
var files = document.getElementById('files')
files.addEventListener('change', function(event) {
console.log(event.target.files)
console.log(
`文件名稱:${event.target.files[0].name}
文件類型:${event.target.files[0].type}
文件大小:${event.target.files[0].size} bytes`
)
})
</script>
複製代碼
實例結果截圖:異步
靠files
集合只能知道一些文件的基本信息,FileReader
類型纔是File API
的重頭戲post
FileReader
類型實現是一種異步文件讀取機制,讀取的是文件系統。能夠經過如下方法讀取文件中的內容ui
方法名 | 參數 | 輸出內容 | 描述 |
---|---|---|---|
readAsText | file,encoding | 純文本 | 異步以純文本形式讀取文件,將讀取到的文本保存在result屬性中 |
readAsDataURL | file | DataURI的形式 | 異步讀取文件並將文本以數據URI的形式保存在result屬性中 |
readAsBinaryString | file | 二進制 | 異步讀取文件內容並將包含文件內容的二進制字符串保存在result屬性中 |
readAsArrayBuffer | file | ArrayBuffer | 異步讀取文件並將一個包含文件內容的ArrayBuffer保存在result屬性中 |
abort | -- | -- | 用於中斷文件讀取過程 |
具體文件輸出代碼:url
<input type='file' id='files'>
<script>
var files = document.getElementById('files')
files.addEventListener('change', function (event) {
let file = event.target.files[0]
let reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = function () {
console.log(reader.result)
}
})
</script>
複製代碼
咱們以上傳圖片,輸出DataURL
爲例spa
其餘三種不一樣的文件輸出,只需將上述reader.readAsDataURL(file)
的代碼替換方法便可,因爲篇幅有限,就不在此展開,讀者能夠建立對應的文件一一嘗試
由於文件讀取過程是異步的,FileReader
也提供了幾個對應的事件,同時在上述的代碼中,咱們也已經使用了FileReader
中的load
事件來判斷是否已經讀完整個文件
事件名稱 | 事件描述 |
---|---|
onabort | 讀取被終止時調用 |
onerror | 讀取出錯時調用 |
onload | 讀取成功時調用 |
onloadend | 讀取完成時調用,無論是讀取成功仍是失敗 |
onloadstart | 讀取將要開始時出發 |
onprogress | 讀取過程當中週期性觸發,每50ms左右觸發一次,能夠用來監聽文件讀取的進度 |
有時候,咱們只想讀取文件的一部分而不是所有內容。爲此,File
對象還支持了一個slice()
方法,slice()
方法接受兩個參數:起始字節數以及要讀取的字節數。這個方法返回一個Blob
實例,Blob是File類型的父類型
咱們新建一個從1到10的txt
,讀取1-5的內容
輸出結果:
如下就是讀取文件部份內容的代碼
<input type='file' id='files'>
<script>
var files = document.getElementById('files')
files.addEventListener('change', function (event) {
let file = event.target.files[0]
let reader = new FileReader()
blob = file.slice(0, 10)
reader.readAsText(blob)
reader.onload = function () {
console.log(reader.result)
}
})
</script>
複製代碼
有時候咱們想要上傳圖片以後,直接在網頁中展現出來,這時候,咱們就可使用對象URL
。
對象URL
也被稱爲blob URL
,指的是引用保存在File
或Blob
中數據的URL
,要建立對象URL
,可使用window.URL.createObjcetURL()
方法,並傳入File
或Blob
對象,方法就會返回一個字符串,指向一塊內存地址。那麼咱們就能夠動態將字符串URL
插入img
標籤中,從而實現網頁上傳圖片展現了
具體代碼以下:
<input type='file' id='files'>
<div id='images'></div>
<script>
var files = document.getElementById('files')
var images = document.getElementById('images')
files.addEventListener('change', function (event) {
let file = event.target.files[0]
url = window.URL.createObjectURL(file)
if (url) {
images.innerHTML = `<img width='300' height='300' src=${url} />`
}
})
</script>
複製代碼
若是已經不須要了相對應的對象URL
數據,最好釋放它佔用的內容。咱們能夠經過將對象URL
傳給window.URL.revokeObjectURL()
,那麼就能手工釋放其佔用的內存
咱們能夠結合HTML5拖拽API
和文件API
,來實現從桌面把文件拖放到對應網頁的目標上。從桌面上把文件拖放到瀏覽器中會觸發drop
事件,從而就能經過event.dataTransfer.files
讀取到拖拽文件的信息
當文件拖拽網頁位置上以後能獲取到文件的信息:
具體代碼以下:
<div id='droptarget' style="width: 200px; height: 200px; border:1px solid black"></div>
<script>
var droptarget = document.getElementById('droptarget')
droptarget.addEventListener('drop', function (event) {
event.preventDefault(); //禁止瀏覽器默認行爲,瀏覽器默認會直接打開顯示
if (event.type === 'drop') {
//獲取文件信息,同File對象相同
var files = event.dataTransfer.files;
console.log(
`文件名稱:${files[0].name},文件類型:${files[0].type},文件大小:${files[0].size} bytes`
)
}
})
droptarget.addEventListener('dragenter', function (event) {
//禁止瀏覽器默認行爲,瀏覽器默認會直接打開顯示
event.preventDefault();
})
droptarget.addEventListener('dragover', function (event) {
//禁止瀏覽器默認行爲,瀏覽器默認會直接打開顯示
event.preventDefault();
})
</script>
複製代碼
咱們已經能夠經過File API
來訪問到文件中的內容,那麼咱們就能夠利用這一點來經過XHR
實現文件的上傳。咱們能夠經過FormData
以表單的方式來上傳文件內容。首先咱們建立一個FormData
對象,經過調用append()
方法並傳入相應的File
對象做爲參數,再經過XHR
的send()
方法,就能夠將文件內容上傳到服務器端。
具體的代碼根據上面的讀取拖拽文件代碼進行改造,從而實現拖拽文件上傳:
droptarget.addEventListener('drop', function (event) {
event.preventDefault();
if (event.type === 'drop') {
var data = new FormData();
var files = event.dataTransfer.files;
data.append("file", files[0]) //若是有多個文件上傳,可對應遍歷files對象加入到data中
var xhr = new XMLHttpRequest();
xhr.open('post', url, true); //url表示文件上傳服務器的地址
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
console.log(xhr.responseText)
}
}
}
xhr.send(data);
})
複製代碼
若是以爲文章對你有幫助,請幫忙多多點贊,動動小手,你的點贊是我寫做最大的動力