閑言: 上篇我們學(xué)習(xí)了一些下載的js前端方式,這篇來講講上傳篇。這也是在項目需求中很常見的O(∩_∩)O。
demo代碼:https://github.com/NARUTOne/DownAndUp.git
參考網(wǎng)址:
http://www.ruanyifeng.com/blog/2012/08/file_upload.html
https://segmentfault.com/a/1190000006600936
https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader
https://developer.mozilla.org/zh-CN/docs/Web/API/File
https://developer.mozilla.org/zh-CN/docs/Web/API/FormData/Using_FormData_Objects
上傳の方式
Form && Input
采用傳統(tǒng)的form表單或異步ajax上傳。至于以前通過iframe來進行異步上傳,這里不詳細介紹惹骂,想了解可以看
http://www.ruanyifeng.com/blog/2012/08/file_upload.html。
<form id="upload-form" action="./upload.do"
onsubmit="return handleSubmit(this)" method="post" enctype="multipart/form-data" >
<div class="filePicker">
<label>點擊選擇文件</label>
<input id="fileInput1" type="file" name="files" multiple="multiple">
</div>
<input type="submit" value="上傳" />
</form>
知識點:
1做瞪、input file標(biāo)簽設(shè)置accept屬性進行文件選擇過濾对粪,該屬性的值必須為一個逗號分割的列表,包含了多個唯一的內(nèi)容類型聲明:
- 以 STOP 字符 (U+002E) 開始的文件擴展名。(例如:".jpg,.png,.doc")
一個有效的 MIME 類型穿扳,但沒有擴展名
- audio/* 表示音頻文件 HTML5
- video/* 表示視頻文件 HTML5
- image/* 表示圖片文件
2衩侥、設(shè)置multiple屬性可以進行設(shè)置為多選。
3矛物、設(shè)置capture屬性可以進行設(shè)置打開攝像拍照或者錄像茫死。multiple屬性和capture屬性不能同時生效。
Capture Image:
<input type="file" accept="image/*" capture="camera">
Capture Audio:
<input type="file" accept="audio/*" capture="microphone">
Capture Video:
<input type="file" accept="video/*" capture="camcorder">
接著采用js來獲取file對象履羞,進行異步上傳峦萎。
var fileInput1 = document.getElementById("fileInput1");
fileInput1.addEventListener('change', function(event) {
var file = fileInput1.files[0];
// 或file = fileInput1.files.item(0);
console.log(file);
document.getElementById('showFile1').innerHTML= file.name
}, false);
function handleSubmit(_this) {
var form = $(_this);
// mulitipart form,如文件上傳類
var formData = new FormData();
formData.append('files', $('#fileInput1')[0].files[0]);
// var formData = new FormData(form[0]);
$.ajax({
type: form.attr('method'),
url: form.attr('action'),
data: formData,
mimeType: "multipart/form-data",
contentType: false,
cache: false,
processData: false
}).success(function (res) {
//成功提交
console.log(res)
document.getElementById('result').innerHTML= '上傳成功'
}).error(function (jqXHR, textStatus, errorThrown) {
//錯誤信息
document.getElementById('result').innerHTML= '上傳失敗'
});
return false;
}
注意:預(yù)防form表單提交的跳轉(zhuǎn)action。
1忆首、ajax中的resquest-header: multipart/form-data
2爱榔、參數(shù)及文件均需要使用new FormData()
實例 append()
file對象:
- lastModifiedDate:文件對象最后修改的日期
- name:文件名,只讀字符串,不包含任何路徑信息.
- size:文件大小,單位為字節(jié),只讀的64位整數(shù).
- type:MIME類型,只讀字符串,如果類型未知,則返回空字符串.
type屬性判斷用戶的文件類型不太準(zhǔn)確,用戶會改變后綴名糙及;size可以做大小限制判斷详幽。
HTML5 拖拽操作文件
HTML5拖拽知識可以參考我以前的拖拽文章:http://www.reibang.com/p/6cd34dfe87fd。
對文件的操作還采用了一些FileReader API的知識浸锨,這個等會下面會簡單介紹哈:-D唇聘。
<div class='demo-box'>
<div class="demo-content">
<a href="javascript:;">選擇圖片文件拖拽至下方框中,實現(xiàn)拖拽上傳及圖片預(yù)覽</a>
<div id="dropbox" class="dropbox">
<div class="area"></div>
</div>
<div id="preview"></div>
</div>
</div>
var dropbox = document.getElementById("dropbox");
var preview = document.getElementById("preview");
dropbox.addEventListener("dragenter", function(e){
e.stopPropagation();
e.preventDefault();
}, false);
dropbox.addEventListener("dragover", function(e){
e.stopPropagation();
e.preventDefault();
}, false);
dropbox.addEventListener("drop", function(e){
e.stopPropagation();
e.preventDefault();
var dt = e.dataTransfer;
var files = dt.files;//獲取文件
for (var i = 0; i < files.length; i++) {
var file = files[i];
var imageType = /^image\//;
if ( !imageType.test(file.type) ) {
continue;
}
// 填充選擇的圖片到展示區(qū)
var img = document.createElement("img");
img.classList.add("obj");
img.file = file;
preview.appendChild(img);
// 讀取File對象中的內(nèi)容
var reader = new FileReader();
reader.onload = (function(aImg) {
return function(e) {
aImg.src = e.target.result;
};
})(img);
reader.readAsDataURL(file);
}
}, false);
FileReader API ##
使用FileReader對象,web應(yīng)用程序可以異步的讀取存儲在用戶計算機上的文件(或者原始數(shù)據(jù)緩沖)內(nèi)容,可以使用File對象或者Blob對象來指定所要處理的文件或數(shù)據(jù).其中File對象可以是來自用戶在一個< input >元素上選擇文件后返回的FileList對象,也可以來自拖放操作生成的 DataTransfer對象,還可以是來自在一個HTMLCanvasElement上執(zhí)行mozGetAsFile()方法后的返回結(jié)果柱搜。
DataURI && URL
URL 是uniform resource locator的縮寫迟郎,在web中的每一個可訪問資源都有一個URL地址,例如圖片聪蘸,HTML文件宪肖,js文件以及style sheet文件表制,我們可以通過這個地址去download這個資源。其實URL是URI的子集控乾,URI是uniform resource identifier的縮寫么介。
URI 是用于獲取資源,包括其附加的信息的一種協(xié)議阱持。附加信息可能是地址夭拌,也可能不是地址魔熏,如果是地址衷咽,那么這時URI就變成URL了。
注意的是data URI不是URL蒜绽,因為它并不包含資源的公共地址镶骗。
DataURI
DataURI對象,允許將一個小文件進行編碼后嵌入到另外一個文檔里躲雅。
data:[<MIME type>][;charset=<charset>][;base64],<encoded data>
eg: data:image/png;base64,xxxxxxxxxxxxx
整體可以視為三部分鼎姊,即聲明:參數(shù)+數(shù)據(jù),逗號左邊的是各種參數(shù)相赁,右邊的是數(shù)據(jù)相寇。
通過FileReader 的readAsDataURL方法獲得:
//讀取File對象中的內(nèi)容
var reader = new FileReader();
reader.onload = (function(aImg) {
return function(e) {
aImg.src = e.target.result; //result屬性中將包含一個data: URL格式的字符串以表示所讀取文件的內(nèi)容.
};
})(img);
reader.readAsDataURL(file);
有時候我們需要將DataURI對象轉(zhuǎn)blob對象:
/**
* dataURI 轉(zhuǎn) blob
* @param {Object} dataURI
*/
function dataURItoBlob(dataURI) {
var arr = dataURI.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});
}
URL對象
我們除了可以使用base64字符串作為內(nèi)容的DataURI將一個文件嵌入到另外一個文檔里,還可以使用URL對象钮科。URL對象用于生成指向File對象或Blob對象的URL唤衫。
var objecturl = window.URL.createObjectURL(file);
靜態(tài)方法會創(chuàng)建一個 DOMString,它的 URL 表示參數(shù)中的對象绵脯。這個 URL 的生命周期和創(chuàng)建它的窗口中的 document 綁定佳励。這個新的URL 對象表示著指定的 File 對象或者 Blob 對象。
window.URL.revokeObjectURL(objecturl)
靜態(tài)方法用來釋放一個之前通過調(diào)用 window.URL.createObjectURL() 創(chuàng)建的已經(jīng)存在的 URL 對象蛆挫。當(dāng)你結(jié)束使用某個 URL 對象時赃承,應(yīng)該通過調(diào)用這個方法來讓瀏覽器知道不再需要保持這個文件的引用了
對象URL來顯示圖片:
window.URL = window.URL || window.webkitURL;
var img = document.createElement("img");
img.src = window.URL.createObjectURL(blob);//二進制對象
img.height = 60;
img.onload = function(e) {
window.URL.revokeObjectURL(this.src);
}
document.body.appendChild(img);
FileReader API詳解:https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader
上傳實例:以二進制流上傳文件
var fileInput = document.getElementById("fileInput");
fileInput.addEventListener('change', function(event) {
var file = fileInput.files[0];
if (file) {
var reader = new FileReader();
var xhr = new XMLHttpRequest();
xhr.onprogress=function(e){
var percentage = Math.round((e.loaded * 100) / e.total);
console.log("percentage:"+percentage);
}
xhr.onload=function(e){
console.log("percentage:100");
}
xhr.open("POST", "這里填寫服務(wù)器地址");
reader.onload = function(evt) {
xhr.send(evt.target.result);
};
reader.readAsBinaryString(file);
}
});
blob對象
BLOB (binary large object),二進制大對象悴侵,是一個可以存儲二進制文件的容器瞧剖。
創(chuàng)建Blob對象的方法有幾種,可以調(diào)用Blob構(gòu)造函數(shù)可免,還可以使用一個已有Blob對象上的slice()方法切出另一個Blob對象抓于,還可以調(diào)用canvas對象上的toBlob方法。
Blob對象有兩個只讀屬性:
- size:二進制數(shù)據(jù)的大小巴元,單位為字節(jié)毡咏。
- type:二進制數(shù)據(jù)的MIME類型,全部為小寫逮刨,如果類型未知呕缭,則該值為空字符串堵泽。在Ajax操作中,如果xhr.responseType設(shè)為blob恢总,接收的就是二進制數(shù)據(jù)迎罗。
** blob創(chuàng)建 **
1)構(gòu)成函數(shù)
Blob構(gòu)造函數(shù),接受兩個參數(shù)片仿。第一個參數(shù)是一個包含實際數(shù)據(jù)的數(shù)組纹安,第二個參數(shù)是數(shù)據(jù)的類型,這兩個參數(shù)都不是必需的砂豌。數(shù)組元素可以是任意多個的ArrayBuffer厢岂,ArrayBufferView (typed array), Blob阳距,或者 DOMString對象塔粒。例如:
var arr = ['<h1>hello world</h1>'];
var blob = new Blob(arr, { "type" : "text/xml" }); // the blob
console.log(blob);
如果在瀏覽器端js生成的內(nèi)容,想讓瀏覽器進行下載要如何辦到呢筐摘?DataURI可以實現(xiàn)這個效果卒茬,但是DataURI的文件類型被限制了,我們這里可以變通一下實現(xiàn)blob對象咖熟。
<a id="aLink">下載</a>
<script type="text/javascript">
function downloadFile (el, fileName, content) {
var aLink = document.querySelector(el);
var blob = new Blob([content]);
aLink.download = fileName;
aLink.href = URL.createObjectURL(blob);
}
document.querySelector('#aLink').addEventListener('click',function () {
downloadFile('#aLink', 'hello.txt', '<h1>hello world</h1>');
})
</script>
2)Blob對象的slice方法生成blob對象
Blob對象的slice方法圃酵,將二進制數(shù)據(jù)按照字節(jié)分塊,返回一個新的Blob對象馍管。
var newBlob = oldBlob.slice(startingByte, endindByte);
大文件分割上傳:
function upload(blobOrFile) {
var xhr = new XMLHttpRequest();
xhr.open('POST', '/server', true);
xhr.onload = function(e) { ... };
xhr.send(blobOrFile);
}
document.querySelector('input[type="file"]').addEventListener('change', function(e) {
var blob = this.files[0];
const BYTES_PER_CHUNK = 1024 * 1024; // 1MB chunk sizes.
const SIZE = blob.size;
var start = 0;
var end = BYTES_PER_CHUNK;
while(start < SIZE) {
upload(blob.slice(start, end));
start = end;
end = start + BYTES_PER_CHUNK;
}
}, false);
終語##
文件上傳下載郭赐,暫時就講這么多哈O(∩_∩)O,智商知識技能有限咽斧,也就只能模仿學(xué)習(xí)到這哈堪置。歡迎大家留言交流,互相進步(????)张惹。
這里給個上傳應(yīng)用的例子(大神制作):前端實現(xiàn)文件的斷點續(xù)傳舀锨。