前端學習(八十三) DOM-檔案(Dom)
File物件
最常見的功能就是頭像上傳,檔案預覽,檔案上傳這些類似的功能
input上的type='file',就可以實現選擇檔案功能
先看一個示例
<div class="div-a"> <input type="file" id="file" class="div-input"> <div class="div-b" id="upfile"></div> </div> <input type="button" value="上傳" id="btn"> <script> let divB=document.getElementById('upfile'), fileS=document.getElementById('file'), btn=document.getElementById('btn'); let a=undefined; fileS.addEventListener('change',function (params) { // console.log(params.target.files); a=params.target.files; //params.target.files獲得的是一個類陣列flieList物件,有length屬性 }) btn.addEventListener('click',function(params){ if(a===undefined){ console.log('尚未選擇檔案'); } else{ //非同步上傳檔案 //console.log(a[0]); let fd=new FormData(); fd.append('file',a[0], a[0].name); let xhr=new XMLHttpRequest(); xhr.open('POST','伺服器地址'); xhr.send() } }) </script>
其中a[0]獲得的就是類似於:File(2554) {name: "changelog.txt", lastModified: 1477137622000, lastModifiedDate: Sat Oct 22 2016 20:00:22 GMT+0800 (中國標準時間), webkitRelativePath: "", size: 2554, …}
這邊就是定了一個input為file,但是實際開發中不會直接使用這種樣式,因此這邊簡單的修飾了一下,將file因此,在file的下面疊加了一個樣式div,選擇檔案後將目標檔案的files屬性賦值給a,點選上傳後將a上傳至伺服器
File物件的屬性(只讀)
屬性 | 說明 |
lastModified | 檔案的最近修改時間,從1970年開始的間隔時間 |
lastModifiedDate | 檔案的最近修改日期,已經不推薦使用 |
name | 檔名 |
webkitRelativePath | 相對於使用者所選擇的資料夾路徑 |
size | 檔案大小,單位是位元組 |
type | 檔案的MIME型別,比如Image/jpeg |
Flie物件的方法
File物件本身沒有任何方法,但是Flie物件繼承自Blob,Blob有一個方法
Blob.slice([start[,end[,contentType]]])
和File結合使用的物件
FlileList
FileList,可以通過input元素的files屬性獲得,或者通過Drag和Drop API獲取使用者拖入到網頁中的檔案列表
<input type='file' id='file' multiple>
加了multiple屬性後,使用者就可以加入多個檔案,這時候的FlieList就是一個類陣列的形式,從下標0開始
屬性/方法
屬性/方法 | 說明 |
length | 包含的檔案個數,只讀 |
item() | 根據索引引數,返回對應的檔案 |
Drag和Drop,拖拽事件
名稱 | 作用 |
---|---|
dragstart | 在拖動時觸發 |
dragend | 在拖動完成時觸發 |
dragenter | 目標元素上繫結dragenter事件,當拖拽元素進入目標元素時觸發 |
dragover | 目標元素上繫結dragover事件, 當拖拽元素在目標元素上移動時觸發 |
drop | 目標元素上繫結drop事件, 並同時取消當前目標元素的dragover的預設事件, 當拖拽元素在目標元素上同時滑鼠放開時觸發事件.例: box為目標元素. box.addEventListener('dragover', function(e){console.log('dragover'); e.preventDefault();}); box.addEventListener('drop', function(e){console.log('drop');}); drop與dragend同時繫結時drop事件先觸發 |
let drop = document.querySelector('.drop');
drop.addEventListener('dragover',function (params) { /*拖動到目標上方的事件*/
params.preventDefault(); /*不要執行與事件關聯的預設動作*/
drop.classList.add('over')
});
drop.addEventListener('drop',function (params) { /*拖動到目標位置且鬆開觸發*/
params.preventDefault();
drop.classList.remove('over');
console.log(params.dataTransfer.files); // 輸出了一個fileList
})
FileReader
用來讀取檔案內容,讀取過程是非同步的,檔案就是FileList的屬性值
屬性(都是隻讀)
屬性 | 說明 |
error | 讀檔案異常時的錯誤資訊 |
readyState | FileReader的狀態,數值 |
result | 檔案內容 |
當中關於readyState的取值
屬性 | 值 | 說明 |
FlileReader.EMPTY | 0 | 尚未載入資料 |
FlieReader.LOADING | 1 | 正在載入資料 |
FileReader.DONE | 2 | 讀取請求已完成 |
物件的方法
屬性 | 說明 |
abort | 終止讀取檔案 |
readAsArrayBuffer | 讀取的檔案內容以ArrayBuffer的形式返回 |
readAsDataURL | 讀取的檔案以data:URL的形式返回 |
readAsText | 讀取的檔案內容以純文字的形式返回 |
readAsBinaryString(非標準) | 讀取的檔案內容以原始二進位制文字的形式返回 |
物件的事件(也就是可監聽的事件)
事件 | 說明 |
onabort | 終止讀取檔案時觸發 |
onerror | 讀取異常時觸發 |
onload | 去讀成功時觸發 |
onloadstart | 開始讀取時觸發 |
onloadend | 讀取完成(可能成功,也可能失敗)時觸發 |
onprogress | 讀取過程中觸發 |
Blob
Blob,二進位制大物件,是binary large object 的縮寫,是用來儲存類似檔案的原始資料。
Blob建構函式
var aBlob=new Blob(array[,options])
- array:陣列
- option:目前納入規範的只有一個type,也就是型別
例如
var af=['<a id="a"><div id="b"></div></a>']
var aBlob=new Blob(af,{type:'text/html'})
方法
silce([start [,end [,contentType]]]):可以切割檔案內容,
- start:起始索引
- end:結束索引
- contentType:指定型別
返回值也是一個blob物件,可以使用這個將大檔案分割成多個小檔案上傳,如果上傳中斷,下次上傳使用相同的方法,可以繼續上傳,但是前段頁面一般不用大檔案上傳,有很多侷限
URL
可以用來建立URL物件,也可以用來建立檔案物件的臨時地址,供使用者或開發者使用,比如本地圖片預覽等
let url=new URL(urlStr,[base])
- urlStr:url字串
- base:如果urlStr是一個相對地址,那麼可以指定它的相對目標地址
示例
var url=new URL('../a','http://www.example.com/dogs')
console.log(url.hostname); //www.example.com
console.log(url.pathname); // /a
方法
方法 | 說明 |
URL.createObjectURL() | 建立物件在瀏覽器中的臨時訪問地址 |
URL.revokeObjectURL() | 回收使用createObjectURL方法建立的臨時訪問地址 |
createObjectURL(object)
接收的是一個引數,最常見的是flle或者Blob,返回的是一個可以在瀏覽器中訪問的地址,這個地址的生命週期是當前視窗,視窗關閉或者重新整理就無效了
revokeObjectURL(url)
引數就是建立的url地址,將其回收,節省瀏覽器的資源
示例:
var obURL=URL.createObjectURL(object);
URL.revokeObjectURL(obURL)
實際案例
限制檔案的型別
<input type="file" id="file" class="div-input" accept="image/*">
只要將input中的設定accept屬性,就可以限制檔案型別(image/*是限制圖片型別),accpet接收的是mime型別,多個值以逗號分隔,比如“image/png,image/jpeg”,也可以寫檔案的字尾名“.png,.jpeg”,也支援萬用字元*,比如“image/*”
限制檔案大小,數量
<input type="file" id="file" class="div-input" accept="image/*" multiple>
只要拿到物件的fileList就可以判斷數量和大小
<div class="div-a">
<input type="file" id="file" class="div-input" accept="image/*" multiple>
<div class="div-b" id="upfile"></div>
</div>
<input type="button" value="上傳" id="btn">
<script>
let divB=document.getElementById('upfile')
fileS.addEventListener('change',function (params) {
if(a.length>3){
console.log('超出上限了');
fileS.value='';
return
}
let exceedSizeFiles=[].slice.call(a).filter(file=>{
return file.size > 10*1024;
})
if(exceedSizeFiles.length){
console.log("檔案最大為10KB");
}
})
</script>
檔案按鈕美化
一種方法是將input隱藏,點選btn時,去關聯點選input
<div class="div-a">
<input type="file" id="file" class="div-input" accept="image/*" multiple>
<div class="div-b" id="upfile"></div>
</div>
<input type="button" value="上傳" id="btn">
<script>
let divB=document.getElementById('upfile'),
fileS=document.getElementById('file'),
btn=document.getElementById('btn');
fileS.addEventListener('change',function (params) {
})
btn.addEventListener('click',function(params){
fileS.click();
})
</script>
另外一種是使用label,通過label的for去關聯input
<div class="div-a">
<label for="file">點選</label>
<input type="file" id="file" class="div-input" accept="image/*" multiple>
</div>
<input type="button" value="上傳" id="btn">
<script>
let divB=document.getElementById('upfile'),
fileS=document.getElementById('file');
fileS.addEventListener('change',function (params) {
})
</script>
label的這種方法可以大大減少關聯程式碼
將文字內容顯示到網頁上
<div class="div-a">
<label for="file">點選</label>
<input type="file" id="file" class="div-input" accept=".txt" >
</div>
<div id="text"></div>
<script>
let divB=document.getElementById('text'),
fileS=document.getElementById('file');
fileS.addEventListener('change',function (params) {
var a=new ReadFile();
a.read(params.target.files[0]);
})
function ReadFile(){
//this.file=file
}
ReadFile.prototype={
constructor:ReadFile,
read:function(file) {
let fr=new FileReader();
fr.onload=function(e){
document.querySelector('#text').innerHTML = e.target.result;
}
fr.readAsText(file)
}
}
</script>
將頁面上的文字建立文字檔案並下載
<textarea id="textbox">此處輸入文字內容</textarea>
<input type="button" id="create" value="建立文字">
<a download="info.txt" id="downloadlink" style='display: none'>下載</a>
<script>
let textFile = null;
let makeTextFile=function(text){
let data= new Blob([text],{type:'text/plain'});
if(textFile !== null){
window.URL.revokeObjectURL(textFile);
}
textFile = window.URL.createObjectURL(data);
return textFile;
}
let create = document.getElementById("create");
let textbox = document.getElementById('textbox');
create.addEventListener('click',function (){
let fileUrl = makeTextFile(textbox.value);
let link = document.getElementById('downloadlink');
link.href = fileUrl;
link.click();
})
</script>
本地圖片預覽:FileReader.readAsDataURL
<input type="file" id="file" accept="image/*">
<script>
let fileInput = document.querySelector('#file');
fileInput.addEventListener('change',e=>{
showImage(e.target.files[0])
})
function showImage(image) {
let fr = new FileReader();
fr.onload= function (params) {
let img = new Image();
img.src = params.target.result;
document.body.appendChild(img)
}
fr.readAsDataURL(image);
}
</script>