前端學習隨記の下載上傳篇 —— 上傳篇

閑言: 上篇我們學習了一些下載的js前端方式,這篇來講講上傳篇。這也是在項目需求中很常見的O(∩_∩)O。

demo代碼:https://github.com/NARUTOne/DownAndUp.git
參考網址:
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

采用傳統的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標簽設置accept屬性進行文件選擇過濾,該屬性的值必須為一個逗號分割的列表,包含了多個唯一的內容類型聲明:

  • 以 STOP 字符 (U+002E) 開始的文件擴展名。(例如:".jpg,.png,.doc")
    一個有效的 MIME 類型,但沒有擴展名
  • audio/* 表示音頻文件 HTML5
  • video/* 表示視頻文件 HTML5
  • image/* 表示圖片文件

2、設置multiple屬性可以進行設置為多選。

3、設置capture屬性可以進行設置打開攝像拍照或者錄像。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;
}

注意:預防form表單提交的跳轉action。
1、ajax中的resquest-header: multipart/form-data
2、參數及文件均需要使用 new FormData() 實例 append()

file對象:

  • lastModifiedDate:文件對象最后修改的日期
  • name:文件名,只讀字符串,不包含任何路徑信息.
  • size:文件大小,單位為字節,只讀的64位整數.
  • type:MIME類型,只讀字符串,如果類型未知,則返回空字符串.

type屬性判斷用戶的文件類型不太準確,用戶會改變后綴名;size可以做大小限制判斷。

HTML5 拖拽操作文件

HTML5拖拽知識可以參考我以前的拖拽文章:http://www.lxweimin.com/p/6cd34dfe87fd
對文件的操作還采用了一些FileReader API的知識,這個等會下面會簡單介紹哈:-D。

<div class='demo-box'>          
    <div class="demo-content">
        <a href="javascript:;">選擇圖片文件拖拽至下方框中,實現拖拽上傳及圖片預覽</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;
        }
        
        // 填充選擇的圖片到展示區
        var img = document.createElement("img");
        img.classList.add("obj");
        img.file = file;
        preview.appendChild(img);
        
        // 讀取File對象中的內容
        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應用程序可以異步的讀取存儲在用戶計算機上的文件(或者原始數據緩沖)內容,可以使用File對象或者Blob對象來指定所要處理的文件或數據.其中File對象可以是來自用戶在一個< input >元素上選擇文件后返回的FileList對象,也可以來自拖放操作生成的 DataTransfer對象,還可以是來自在一個HTMLCanvasElement上執行mozGetAsFile()方法后的返回結果。

DataURI && URL

URL 是uniform resource locator的縮寫,在web中的每一個可訪問資源都有一個URL地址,例如圖片,HTML文件,js文件以及style sheet文件,我們可以通過這個地址去download這個資源。其實URL是URI的子集,URI是uniform resource identifier的縮寫。
URI 是用于獲取資源,包括其附加的信息的一種協議。附加信息可能是地址,也可能不是地址,如果是地址,那么這時URI就變成URL了。
注意的是data URI不是URL,因為它并不包含資源的公共地址。

DataURI
DataURI對象,允許將一個小文件進行編碼后嵌入到另外一個文檔里。

data:[<MIME type>][;charset=<charset>][;base64],<encoded data>
eg: data:image/png;base64,xxxxxxxxxxxxx

整體可以視為三部分,即聲明:參數+數據,逗號左邊的是各種參數,右邊的是數據。

通過FileReader 的readAsDataURL方法獲得:

//讀取File對象中的內容
var reader = new FileReader();
reader.onload = (function(aImg) { 
  return function(e) { 
    aImg.src = e.target.result; //result屬性中將包含一個data: URL格式的字符串以表示所讀取文件的內容.
  }; 
})(img);
reader.readAsDataURL(file);

有時候我們需要將DataURI對象轉blob對象:

/**
 * dataURI 轉 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字符串作為內容的DataURI將一個文件嵌入到另外一個文檔里,還可以使用URL對象。URL對象用于生成指向File對象或Blob對象的URL。

var objecturl = window.URL.createObjectURL(file);

靜態方法會創建一個 DOMString,它的 URL 表示參數中的對象。這個 URL 的生命周期和創建它的窗口中的 document 綁定。這個新的URL 對象表示著指定的 File 對象或者 Blob 對象。

window.URL.revokeObjectURL(objecturl)

靜態方法用來釋放一個之前通過調用 window.URL.createObjectURL() 創建的已經存在的 URL 對象。當你結束使用某個 URL 對象時,應該通過調用這個方法來讓瀏覽器知道不再需要保持這個文件的引用了

對象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", "這里填寫服務器地址");  
        reader.onload = function(evt) {
            xhr.send(evt.target.result);
        };
        reader.readAsBinaryString(file);
    }
});         

blob對象

BLOB (binary large object),二進制大對象,是一個可以存儲二進制文件的容器。

創建Blob對象的方法有幾種,可以調用Blob構造函數,還可以使用一個已有Blob對象上的slice()方法切出另一個Blob對象,還可以調用canvas對象上的toBlob方法。

Blob對象有兩個只讀屬性:

  • size:二進制數據的大小,單位為字節。
  • type:二進制數據的MIME類型,全部為小寫,如果類型未知,則該值為空字符串。在Ajax操作中,如果xhr.responseType設為blob,接收的就是二進制數據。

** blob創建 **

1)構成函數
Blob構造函數,接受兩個參數。第一個參數是一個包含實際數據的數組,第二個參數是數據的類型,這兩個參數都不是必需的。數組元素可以是任意多個的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生成的內容,想讓瀏覽器進行下載要如何辦到呢?DataURI可以實現這個效果,但是DataURI的文件類型被限制了,我們這里可以變通一下實現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方法,將二進制數據按照字節分塊,返回一個新的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,智商知識技能有限,也就只能模仿學習到這哈。歡迎大家留言交流,互相進步(????)。
這里給個上傳應用的例子(大神制作):前端實現文件的斷點續傳

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,936評論 6 535
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,744評論 3 421
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,879評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,181評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,935評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,325評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,384評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,534評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,084評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,892評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,067評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,623評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,322評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,735評論 0 27
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,990評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,800評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,084評論 2 375

推薦閱讀更多精彩內容

  • 前端學習隨記の下載上傳篇 —— 下載篇 閑言: 懶懶懶!!!好長時間不寫文章了,一直出差魔都,學習一些其他知識開發...
    迷緣火葉閱讀 1,181評論 0 2
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,799評論 18 139
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,726評論 18 399
  • 前言 HTML5 中提供的文件API在前端中有著豐富的應用,上傳、下載、讀取內容等在日常的交互中很常見。而且在各個...
    linshuai閱讀 904評論 0 11
  • 婆婆喜歡做面食,每次和好面之后都把面放在盆里靜置一段時間,說得讓面“餳一餳”,我問為什么,她說這樣做出來才好吃。 ...
    今小汐閱讀 357評論 7 4