1.簡介
在Html5中提供了一種通過File API規(guī)范與本地文件進(jìn)行交互的標(biāo)準(zhǔn)方法。在使用 File API 在向服務(wù)器發(fā)送圖片的過程中可以創(chuàng)建圖片的縮略圖預(yù)覽,也可以允許應(yīng)用程序在用戶離線時(shí)保存文件引用。另外弦牡,您可以使用客戶端邏輯來驗(yàn)證上傳內(nèi)容的 type 與其文件擴(kuò)展名是否匹配灭将,或者限制上傳內(nèi)容的大小泄伪。
該規(guī)范通過“本地”文件系統(tǒng)提供了多種文件訪問接口:
1.1 FileList 對象
filelist對象是針對表單的file控件挫望,當(dāng)用戶利用file控件選取文件以后立润,這個(gè)控件的files屬性就是filelist對象。
//使用多選控件
<input type='file' id="file-test" multiple />
<script>
document.getElementById('file-test').onchange = function() {
console.log(this.files);
};
</script>
注:除了file控件以外媳板,采用拖放的方式桑腮,也可以得到filelist對象。一般情況下蛉幸,filelist對象只能被動(dòng)的讀取破讨,不可以手動(dòng)構(gòu)造,只有在user主動(dòng)觸發(fā)(選取或拖拽)了文件讀取的行為奕纫,javascript才會(huì)訪問到filelist提陶。
1.2 File對象
在filelist對象中就包括了file對象,file對象含有以下的屬性:
name: 文件名匹层,只讀屬性隙笆;
size: 文件大小,單位為字節(jié)升筏,只讀屬性撑柔;
type: 文件的MIME類型,若是分辨不出類型您访,則為空字符串铅忿,只讀屬性;
lastModified:文件的上次修改時(shí)間灵汪,格式為時(shí)間戳檀训;
lastModifiedDate:文件上次修改時(shí)間,格式為Date對象實(shí)例识虚。
如下圖所示:
1.3 Blob對象
Blob(Binary Large Object)對象代表了一段二進(jìn)制數(shù)據(jù)肢扯,提供了一系列操作接口,其他二進(jìn)制數(shù)據(jù)的API(比如File對象)担锤,都是建立在Blob對象基礎(chǔ)上的蔚晨,繼承了它的屬性和方法。
生成Blob對象有兩種方法:一種是使用Blob構(gòu)造函數(shù)肛循,另一中是對現(xiàn)有的Blob對象使用slice方法切出一部分铭腕。
1.4 FileReader
FileReader對象用于讀取文件,他的參數(shù)是file對象或blob對象多糠。對于不同類型的文件累舷,F(xiàn)ileReader提供了不同的讀取方法:
- readerAsText(blob|File,opt_encoding) :
返回文本字符串,默認(rèn)情況下夹孔,文本編碼格式是UTF-8被盈,可以通過可選參數(shù)指定其他編碼格式的文本析孽。 - readerAsDataURL(Blob|File) :
返回一個(gè)基于Base64編碼的data-uri對象(可用于<img>標(biāo)簽中的src屬性,從而達(dá)到圖片預(yù)覽的效果)只怎。 - readerAsArrayBuffer(Blob|File) :
返回一個(gè)ArrayBuffer對象袜瞬。
FileReader對象采用異步方式讀取文件,可以為一系列的事件指定回調(diào)函數(shù)身堡。
- onabort() 方法 :讀取中段或者調(diào)用reader.abort()方法時(shí)觸發(fā)邓尤。
- onerror() 方法 :讀取出錯(cuò)時(shí)觸發(fā)。
- onload() 方法 :讀取成功后觸發(fā)贴谎。
- onloadend() 方法 :讀取完成后觸發(fā)汞扎,不管是否成功。觸發(fā)順序排在onload或onerror后面擅这。
- onloadstart() 方法 :讀取將要開始時(shí)觸發(fā)澈魄。
- onprogress() 方法 :讀取過程中周期性觸發(fā)(一般可用于獲取文件的讀取進(jìn)度)。
1.5 createObjectURL 方法
調(diào)用URL對象的createObjectURL方法蕾哟,傳入一個(gè)File對象或者Blob對象一忱,能生成一個(gè)鏈接。這個(gè)URL可以放置于任何通程啡罚可以放置URL的地方帘营,比如<img>標(biāo)簽的src屬性。需注意的是即使是同樣的二進(jìn)制數(shù)據(jù)逐哈,每調(diào)用一次URL.createObjectURL方法芬迄。就會(huì)得到一個(gè)不一樣的URL。
var URL = window.URL || window.webkitURL || window.mozURL ;
var SRC = URL.createObjectURL(file);
1.6 onprogress 事件
想要上傳圖片的時(shí)候顯示進(jìn)度條昂秃,在HTML5中提供了onprogress事件禀梳。onprogress事件可以作用于<video>或<audio>標(biāo)簽中,作為其狀態(tài)回調(diào)函數(shù)的作用肠骆。也可以作為XMLHttpRequest的指定事件算途,XMLHttpRequest對象在傳遞數(shù)據(jù)的時(shí)候,提供了一個(gè)progress事件蚀腿,用于返回進(jìn)度信息嘴瓤。它分為 上傳 和 下載 兩種情況:
- 下載的 progress 事件屬于 XMLHttpRequest 對象
- 上傳的 progress 事件屬于 XMLHttpRequest.upload 對象
當(dāng)上傳或者下載時(shí),會(huì)頻繁調(diào)用該方法莉钙。該方法接受一個(gè)事件參數(shù)event,其中event.total是需要傳輸?shù)目傋止?jié)廓脆,event.loaded是已經(jīng)傳輸?shù)淖止?jié)。如果event.lengthComputable 不為真磁玉,則event.total等于0停忿。
示例代碼:
<body>
<input type="file" id="file">
<div class="progress">
<div></div>
</div>
<button onclick="ajaxUpload()">上傳</button>
<script>
function ajaxUpload() {
var file = $('#file').get(0).files[0];
var formdata = new FormData();
formdata.append('file', file);
$.ajax({
url: 'test_progress.php',
type: 'post',
dataType: 'json',
data: formdata,//這里上傳的數(shù)據(jù)使用了formData 對象
processData: false, //必須false才會(huì)自動(dòng)加上正確的Content-Type
contentType: false, //必須設(shè)置
//這里我們先拿到j(luò)Query產(chǎn)生的 XMLHttpRequest對象,為其增加 progress 事件綁定蚊伞,然后再返回交給ajax使用.
xhr: () => {
var xhr = new XMLHttpRequest();
xhr.upload.onprogress = (evt) => {
console.log(evt);
var progressWidth = (evt.loaded / evt.total) * 100 + '%';
$('.progress > div').css('width', progressWidth);
}
return xhr;
}
})
}
</script>
</body>
2.檢查環(huán)境
在編寫前請先檢查您當(dāng)前的瀏覽器是否支持File API:
if(window.File &&window.FileReader &&window.FileList &&window.Blob) {
alert( "Success! The File APIs are fully supported in this browser")
}else{
alert('The File APIs are not fully supported in this browser.');
}
3.選取文件
3.1 通過表單輸入進(jìn)行選取文件
選取文件最常用的方法就死使用標(biāo)準(zhǔn)的<input type="file">元素席赂,JS會(huì)返回選定的File對象的列表吮铭,下面的示例是使用“multiple”屬性實(shí)現(xiàn)同時(shí)選定多個(gè)文件:
<div style="margin:0 auto;width:400px;height:200px;border:2px dashed pink">
<input type="file" id="filetest" name="filetest" multiple />
<output id="filelist"></output>
</div>
<script>
function handleFileSelect(event){
var files = event.target.files;
var output = [];
var i,f;
for(i=0;f=files[i];i++){
output.push('<li><strong>',f.name,'</strong>','-',f.size, 'bytes,last modified:',f.lastModifiedDate,'</li>');
}
document.getElementById("filelist").innerHTML = '<ul>'+output.join('')+'</ul>';
}
document.getElementById("filetest").addEventListener('change',handleFileSelect,false);
</script>
3.2 通過拖拽選取文件并顯示縮略圖
該方法是在本地將文件從桌面拖放到瀏覽器進(jìn)行選取,并顯示圖片的縮略圖氧枣,具體示例如下:
<style>
.thumb {
height: 80px;
border: 1px solid #eee;
margin: 10px 5px 0 0;
}
</style>
<body>
<div style="width: 320px;margin: 0 auto;border:2px solid skyblue;padding:10px;">
<div id="drop_zone" style="border:2px dashed pink;color:#bbb;text-align: center;line-height:76px;">Drop files here</div>
<output id="list"></output>
</div>
<script>
$(document).ready(function() {
function handleFileSelect(evt) {
evt.stopPropagation();
evt.preventDefault();
var files = evt.dataTransfer.files; // 拖拽選取時(shí)沐兵,F(xiàn)ileList 對象格式.
var i,f;
for (i = 0; f = files[i]; i++) {
// 匹配圖片格式
if (!f.type.match('image.*')) {
continue;
}
var reader = new FileReader(); //讀取文件信息
// 捕獲文件信息的閉包
reader.onload = (function(theFile) {
return function(e) {
// 顯示縮略圖
var span = document.createElement('span');
span.innerHTML = ['<img class="thumb" src="', e.target.result,
'" title="', escape(theFile.name), '"/>'].join('');
document.getElementById('list').insertBefore(span, null);
};
})(f);
// 以URL的形式讀入圖像文件。
reader.readAsDataURL(f);
}
}
function handleDragOver(evt) {
evt.stopPropagation();
evt.preventDefault();
evt.dataTransfer.dropEffect = 'copy';
}
// 設(shè)置dnd時(shí)間偵聽器便监。
var dropZone = document.getElementById('drop_zone');
dropZone.addEventListener('dragover', handleDragOver, false);
dropZone.addEventListener('drop', handleFileSelect, false);
})
</script>
示例顯示結(jié)果如下:
3.2 監(jiān)聽上傳進(jìn)度
在HTML5中,提供了一個(gè)FormData對象碳想,能關(guān)于模擬一個(gè)原始的表單格式的數(shù)據(jù)烧董,在之前的表單數(shù)據(jù)傳輸中,必須要用form標(biāo)簽將要傳輸?shù)臄?shù)據(jù)包裹起來了胧奔,按照規(guī)定的格式與后臺傳輸逊移,HTML5中的FormData對象就模擬這種格式,將form表單元素的value值與對應(yīng)的name屬性結(jié)合起來龙填,組成一個(gè)querystring字符串胳泉。下面示例結(jié)合FormData實(shí)現(xiàn)通過onprogress事件監(jiān)控讀取狀態(tài),并以進(jìn)度條的形式顯示出來岩遗。
示例代碼如下:
<div style="text-align: center; padding-top: 50px">
<input type="file" id="avatarfile" accept="image/png, image/jpeg, image/jpg, video/*"/>
<button onclick="to_upload_file()">上傳文件</button>
<br>
<div style="text-align: left;margin-top: 15px;display: inline-block;width: 300px; height: 20px; border: 1px solid #44A1F8; border-radius: 2px;position: relative">
<div id="progress_bar" style="display: inline-block; width: 0px; height: 20px;background-color: #64B587"></div>
<div style="text-align: center;width: 300px;position: absolute; top: 0; font-size:16px; color: #413F43">
<div id="loading-percent">
上傳進(jìn)度0%
</div>
</div>
</div>
</div>
<script>
function to_upload_file(){
var fileObj = document.getElementById("avatarfile").files[0]
if(fileObj){
var formContent = new FormData();
formContent.append("file", fileObj);
var xhr = new XMLHttpRequest();
xhr.upload.onprogress = (e)=>{
var progress_bar = document.getElementById("progress_bar");
var loadingPercent = document.getElementById("loading-percent");
if(e.lengthComputable){
var loading = Math.round(e.loaded / e.total * 100);
}
if(loading === 100){
loadingPercent.innerHTML = "上傳成功^_^";
}else{
loadingPercent.innerHTML = "上傳進(jìn)度"+loading+"%"
}
progress_bar.style.width = String(loading * 3) + "px";
}; // 監(jiān)聽上傳進(jìn)度
xhr.upload.onload = (e)=>{console.log("Success !", e)}; // 上傳成功后的回調(diào)函數(shù)
xhr.upload.onerror = (e)=>{console.log("Failed", e)}; // 上傳失敗后的回調(diào)函數(shù)
xhr.open("POST", "http://127.0.0.1/upload_test.php", true);
xhr.send(formContent);
}else{
alert("當(dāng)前無上傳文件扇商,請先選擇文件后再上傳")
}
}
</script>
參考文件:
http://www.reibang.com/p/b3e986fb1237
http://www.w3.org/TR/file-upload