平時工做中常常會遇到須要上傳文件的狀況,若是你用ant design 或者element ,它們都提供了上傳的組件。 咱們分別來看一下element 和 antd 手動上傳怎麼處理:javascript
antd官網有手動上傳的demo:
在這裏簡單寫一寫實現,主要有 在jsx中引入Upload組件,將 fileList 做爲props傳入,fileList爲選擇的文件列表,和 上傳函數的實現。php
// jsx <div> <Upload fileList={this.state.fileList}> // Upload 爲上傳組件 <Button> <Icon type="upload" /> Select File </Button> </Upload> <Button onClick={this.handleUpload}> 上傳文件 </Button> </div>
// handleUpload 的實現 使用 fetch 請求 const handleUpload = () { const formData = new FormData(); fileList.forEach((file) => { // fileList 是要上傳的文件數組 formData.append('files[]', file); }); fetch(url: 'http:just.a.url.demo', { method: 'POST', headers: { credentials: 'same-origin' // 'Content-Type': 'multipart/form-data' // 不要加上這個文件類型說明 }, body: formData }) .then(response => response.json()) .catch(error => console.error('Error:', error)) .then(response => console.log('Success:', response)); }
element 和antd 不一樣,經過上傳組件拿回的數據,element又封裝了一層,因此傳數據稍有不一樣。
如下是簡單實現:html
// template <el-upload :file-list="fileList" :auto-upload="false"> <el-button slot="trigger" type="primary">選擇文件</el-button> <el-button @click="submitUpload">上傳文件</el-button> </el-upload> // 上傳實現 const handleUpload = () { const formData = new FormData(); fileList.forEach((file) => { formData.append('files[]', file.raw); // 這裏與antd 不一樣的是,文件真正數據爲 file.raw }); fetch(url: 'http:just.a.url.demo', { method: 'POST', headers: { credentials: 'same-origin' // 'Content-Type': 'multipart/form-data' // 不要加上這個文件類型說明 }, body: formData }) .then(response => response.json()) .catch(error => console.error('Error:', error)) .then(response => console.log('Success:', response)); }
雖然能夠找得demo把文件傳輸了出去,可是內心有幾個問題,以下:java
從傳文件的歷史來回答傳文件問什麼須要FormData 格式。ajax
在最開始的時候,文件上傳的傳統形式是使用 表單元素file。參照下面的代碼:chrome
<form id="upload-form" action="upload.php" method="post" enctype="multipart/form-data" > <input type="file" id="upload" name="upload" /> <br /> <input type="submit" value="Upload" /> </form>
它在chrome瀏覽器中是這個樣子:
json
選擇文件以後,點擊Upload 按鈕,文件開始上傳。api
使用form元素比較簡單,但缺點也比較明顯:上傳同步、上傳完成頁面會刷新;
在HTML5出現以前,想要實現文件異步上傳,只能經過iframe+form實現;
其原理是:文件上傳時在頁面中動態建立一個iframe元素和一個form元素,並將form元素的target屬性指向動態建立iframe元素。當用戶完成選擇文件動做時,提交子頁面中的 form。這時,iframe跳轉,而父頁面沒有刷新。這使得上傳結束後,服務器處理結果返回到動態iframe窗口而沒有刷新頁面;
具體code,這裏再也不枚舉,感興趣童鞋能夠去 iframe+form 查看。數組
哎呀,終於來到了現代社會,而且見到了我們的主角 FormData。 ajax 你們確定都知道了,異步刷新,無需從新加載整個網頁的狀況下,便可以更新部分網頁。
那FormData 是什麼呢? FormData是XMLHttpRequest Level 2添加的一個新接口,他能夠 構建相似表單的鍵值對, 也就是說咱們能夠利用 FormData 來模擬表單控件,而後使用XMLHttpRequest的send()
方法來異步的提交這個"表單"。
看一下簡單的使用 FormData傳文件的例子瀏覽器
<body> <input type="file" id="upload" name="upload" /> <input type="button" value="提交" onclick="demoUpload()" /> <script type="text/javascript"> function demoUpload() { console.log('submit'); var myFile = document.getElementById('upload').files[0]; var xhr = new XMLHttpRequest(); var formData = new FormData(); var url = 'http://hqy.qunar.com:8080/'; // for (var key in params) { // formData.append(key, params[key]); // } formData.append('uploadFile', myFile); // 文件 formData.append('name', 'qunar'); // 其它數據 xhr.open('POST', url, true); //這裏的url爲本地起的一個服務地址 xhr.send(formData); } </script> </body>
選擇文件並上傳後,經過瀏覽器看看網絡狀況。
囉囉嗦嗦這麼多,終於知道了爲何傳文件要用FormData了!!開心,簡單來講就是,傳文件一開始設計使用 form 來傳,可是呢,使用form默認的上傳方式存在諸多問題,好比同步啦,我想在上傳以前處理一下數據啦,這個時候FormData 就站出來了,大喊 我能夠構建相似表單的鍵值對,來模擬表單,發送的數據用我構建的對象就能夠上傳文件了。今後咱們上傳文件就歡欣鼓舞的來找FormData了。
好了,另外一個小問題,文件和其餘數據的不一樣,文件傳輸時是二進制數據,因此格式和通常數據不同。 咱們的FormData大俠不只能夠傳文件也能夠傳通常數據哦,固然傳輸數據有不少種方式,好比get請求的時候跟在url後面。
認真看過問題1的回答,這個問題就很簡單了。fetch api 是一個提供請求資源(包括經過網絡)的接口,它和xhr(XMLHttpRequest)相似。
因此請求不是爲何要用fetch,而是fetch 只是一種方法,能夠用fetch也能夠用xhr(參考問題一中的 ajax + FormData demo),他們邏輯上是‘並列’的。
至於問和AJAX 什麼關係,不如說 Ajax 和 xhr什麼關係。由於Ajax的核心是XMLHttpRequest對象, Ajax異步的實現是經過new 一個 XMLHttpRequest對象,通常簡稱該對象對xhr。因此這裏 fetch 是Ajax或XMLHttpRequest的一個替代方案。
當指定爲'multipart/form-data'的時候,還須要指定 boundary=something。若是不指定則會自動分配。
ps: 這些回答基於本身理解,若有不妥,但願路過的大神輕噴,指正。
MDN上這樣解釋FormData:
The FormData interface provides a way to easily construct a set of key/value pairs representing form fields and their values, which can then be easily sent using the XMLHttpRequest.send() method.It uses the same format a form would use if the encoding type were set to "multipart/form-data".
FormData 接口提供了一種方法,能夠方便地構造一組表示表單字段和它們的值的鍵值對,而後可使用XMLHtRPROQuest.send()方法輕鬆發送。若是一個表單設置編碼格式爲 multipart/form-data
, 這個表單將和FormData 使用相同的格式。
MDN 這樣介紹Fetch,Fetch API 是和XHR相似的用於獲取資源(包括經過網絡)的一種接口方法,可是 Fetch API提供了更強大更靈活的API。fetch()即是其中一個全局方法。
Fetch和XHR平行關係,
先來看fetch()幾種常見的用法:
var url = 'https://example.com/profile'; var data = {username: 'example'}; fetch(url, { method: 'POST', // or 'PUT' body: JSON.stringify(data), // data can be `string` or {object}! headers:{ 'Content-Type': 'application/json' } }).then(res => res.json()) .catch(error => console.error('Error:', error)) .then(response => console.log('Success:', response));
var formData = new FormData(); var fileField = document.querySelector("input[type='file']"); formData.append('username', 'abc123'); formData.append('avatar', fileField.files[0]); fetch('https://example.com/profile/avatar', { method: 'POST', body: formData }) .then(response => response.json()) .catch(error => console.error('Error:', error)) .then(response => console.log('Success:', response));