本文內容如下:
一. FormData簡介
二. Ajax使用FormData上傳文件
三. Ajax使用FormData上傳多個文件
四. Ajax使用FormData上傳文件綜合拓展
一. FormData簡介
參考: https://segmentfault.com/a/1190000006716454
https://www.cnblogs.com/jpfss/p/8960806.html
1. 概述
FormData類型其實是在XMLHttpRequest 2級定義的,它是為序列化表以及創建與表單格式相同的數據(當然是用於XHR傳輸)提供便利。
2. 構造函數
創建一個formData對象實例有幾種方式
1、創建一個空對象
實例
var formData = new FormData();
此時可以調用append()方法來添加數據
2、使用已有的表單來初始化一個對象實例
假如現在頁面已經有一個表單
<form id="myForm" action="" method="post"> <input type="text" name="name">名字 <input type="password" name="psw">密碼 <input type="submit" value="提交"> </form>
我們可以使用這個表單元素作為初始化參數,來實例化一個formData對象
// 獲取頁面已有的一個form表單 var form = document.getElementById("myForm"); // 用表單來初始化 var formData = new FormData(form); // 我們可以根據name來訪問表單中的字段 var name = formData.get("name"); // 獲取名字 var psw = formData.get("psw"); // 獲取密碼
// 當然也可以在此基礎上,添加其他數據 formData.append("token","kshdfiwi3rh");
注: 通過 FormData.append()方法賦給字段的值若是數字會被自動轉換為字符(字段的值可以是一個Blob對象,一個File對象,或者一個字符串,剩下其他類型的值都會被自動轉換成字符串).
3. 操作方法
首先,我們要明確formData里面存儲的數據形式,一對key/value組成一條數據,key是唯一的,一個key可能對應多個value。如果是使用表單初始化,每一個表單字段對應一條數據,它們的HTML name屬性即為key值,它們value屬性對應value值。
key | value |
---|---|
k1 | [v1,v2,v3] |
k2 | v4 |
3.1 獲取值
我們可以通過get(key)/getAll(key)來獲取對應的value
formData.get("name"); // 獲取key為name的第一個值 formData.getAll("name"); // 返回一個數組,獲取key為name的所有值
3.2 添加數據
我們可以通過append(key, value)來添加數據,如果指定的key不存在則會新增一條數據,如果key存在,則添加到數據的末尾
formData.append("k1", "v1"); formData.append("k1", "v2"); formData.append("k1", "v1"); formData.get("k1"); // "v1" formData.getAll("k1"); // ["v1","v2","v1"]
3.3 設置修改數據
我們可以通過set(key, value)來設置修改數據,如果指定的key不存在則會新增一條,如果存在,則會修改對應的value值。
formData.append("k1", "v1"); formData.set("k1", "1"); formData.getAll("k1"); // ["1"]
3.4 判斷是否該數據
有的瀏覽器未實現has()的方式,使用時需注意
我們可以通過has(key)來判斷是否對應的key值
formData.append("k1", "v1"); formData.append("k2",null); formData.has("k1"); // true formData.has("k2"); // true formData.has("k3"); // false
3.5 刪除數據
通過delete(key),來刪除數據
formData.append("k1", "v1"); formData.append("k1", "v2"); formData.append("k1", "v1"); formData.delete("k1"); formData.getAll("k1"); // []
3.6 遍歷
我們可以通過entries()來獲取一個迭代器,然后遍歷所有的數據,
formData.append("k1", "v1"); formData.append("k1", "v2"); formData.append("k2", "v1"); var i = formData.entries(); i.next(); // {done:false, value:["k1", "v1"]} i.next(); // {done:false, value:["k1", "v2"]} i.next(); // {done:false, value:["k2", "v1"]} i.next(); // {done:true, value:undefined}
可以看到返回迭代器的規則
-
-
每調用一次next()返回一條數據,數據的順序由添加的順序決定
-
返回的是一個對象,當其done屬性為true時,說明已經遍歷完所有的數據,這個也可以作為判斷的依據
-
返回的對象的value屬性以數組形式存儲了一對key/value,數組下標0為key,下標1為value,如果一個key值對應多個value,會變成多對key/value返回
-
我們也可以通過values()方法只獲取value值
formData.append("k1", "v1"); formData.append("k1", "v2"); formData.append("k2", "v1"); var i = formData.values(); i.next(); // {done:false, value:"v1"} i.next(); // {done:fase, value:"v2"} i.next(); // {done:fase, value:"v1"} i.next(); // {done:true, value:undefined}
4. 發送數據
我們可以通過xhr來發送數據
var xhr = new XMLHttpRequest(); xhr.open("post","login"); xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); xhr.send(formData);
這種方式可以來實現文件的異步上傳。
二. Ajax使用FormData上傳文件
1.使用<form>表單初始化FormData對象方式上傳文件
HTML代碼:
<form id="uploadForm" enctype="multipart/form-data"> <input id="file" type="file" name="file"/> <button id="upload" type="button">upload</button> </form>
javascript代碼
$("#upload").click(function () { $.ajax({ url: '/Default/UploadFile', type: 'POST', cache: false, data: new FormData($('#uploadForm')[0]), processData: false, contentType: false, success: function (data) { alert(data.result) } }).fail(function (res) { alert("系統錯誤") }); });
這里要注意幾點:
-
processData
設置為false
。因為data
值是FormData
對象,不需要對數據做處理。<form>
標簽添加enctype="multipart/form-data"
屬性。cache
設置為false
,上傳文件不需要緩存。contentType
設置為false,不設置contentType值,
因為是由<form>
表單構造的FormData
對象,且已經聲明了屬性enctype="multipart/form-data"
,所以這里設置為false。
上傳后,服務器端代碼需要使用從查詢參數名為file
獲取文件輸入流對象,因為<input>
中聲明的是name="file"
。
后台代碼:
[HttpGet] public IActionResult UploadFile() { return View(); } [HttpPost] public async Task<IActionResult> UploadFile(IFormFile file) { string oFileName = Path.GetFileName(file.FileName); if (!string.IsNullOrEmpty(oFileName)) { return Json(new { Result = "Success", Message = "" }); } return Json(new { Result = "Failed", Message = "" }); }
2.使用FormData對象添加字段方式上傳文件
HTML代碼:
<div id="uploadForm"> <input id="file" type="file" /> <button id="upload" type="button">upload</button> </div>
javascript代碼
$("#upload").click(function () { var formData = new FormData(); formData.append('file', $('#file')[0].files[0]); $.ajax({ url: '/Default/UploadFileByFormData', type: 'POST', cache: false, data: formData, processData: false, contentType: false, success: function (data) { alert(data.result) } }).fail(function (res) { alert("系統錯誤") }); });
這里有幾處不一樣:
-
append()
的第二個參數應是文件對象,即$('#file')[0].files[0]
。contentType
也要設置為‘false’。
從代碼$('#file')[0].files[0]
中可以看到一個<input type="file">
標簽能夠上傳多個文件,
只需要在<input type="file">
里添加multiple
或multiple="multiple"
屬性。
后台代碼
public async Task<IActionResult> UploadFileByFormData(IFormFile file) { string oFileName = Path.GetFileName(file.FileName); if (!string.IsNullOrEmpty(oFileName)) { return Json(new { Result = "Success", Message = "" }); } return Json(new { Result = "Failed", Message = "" }); }
三. Ajax使用FormData上傳多個文件
在<input type="file">
里添加multiple="multiple"
屬性,選擇文件時,按住Ctrl鍵或Shift鍵選擇多個文件
HTML代碼
<div id="uploadForm"> <input id="file" type="file" multiple="multiple" /> <button id="upload" type="button">upload</button> </div>
javascript代碼
<script type="text/javascript"> $("#upload").click(function () { var formData = new FormData(); for (var i = 0; i < $('#file')[0].files.length; i++) { formData.append('files', $('#file')[0].files[i]); } $.ajax({ url: '/Default/UploadFilesByFormData', type: 'POST', cache: false, data: formData, processData: false, contentType: false, success: function (data) { alert(data.message) } }).fail(function (res) { alert("系統錯誤") }); }); </script>
后台代碼
public async Task<IActionResult> UploadFilesByFormData(IFormFile[] files) { string fileNames = ""; for (int i = 0; i < files.Length; i++) { fileNames += files[i].FileName+"; "; } return Json(new { Result = "Success", Message = fileNames }); }
四. Ajax使用FormData上傳文件綜合拓展
通過在<input type="file">
里添加multiple="multiple"
屬性,雖然能夠實現一次長傳多個文件,但是並不能顯示多個文件的文件名,也不能對選中的文件進行刪除,新增的操作,以下實例是優化后的多個文件上傳。
實現效果如下:
HTML代碼:
<table> <tr style="width:100%;"> <td style="width:150px; text-align:right;line-height:40px;"><label style="margin-top:8px;">附件上傳:</label></td> <td colspan="3" style="margin-left:50px;text-align:left;line-height:40px;"> <img src="~/images/附件.png" style="height:10%" /> <input id="file" type="file" style="display:none;" onchange="AddFile()" /> <span id="sfile" onclick="document.getElementById('file').click()" style="line-height:40px;color:gray;font-weight:600;"> Add File</span> </td> </tr> </table> <div id="divShowFile"> </div> <button id="upload" type="button" style="margin-left:150px;">upload</button>
<style type="text/css"> #sfile:hover { text-decoration: underline; cursor: pointer; color: blue; } </style>
javascript代碼
<script type="text/javascript"> var FileData = new FormData();//保存File文件 var num = 0;//保存file文件id序號 function AddFile() { var isonly = "T"; var fileid = "file" + num; var pid = "p" + num; var lblid = "lbl" + num; var filePath = $('#file').val(); if (filePath.trim() != "") {//選擇了上傳文件 //遍歷FileData,看是否有重復數據 $(".lblfile").each(function () { if (filePath == $(this).text()) { isonly = "F"; alert("File has upload"); } }); if (isonly == "T") { //將上傳的文件添加到全局變量FileData中 FileData.append(fileid, $('#file')[0].files[0]); //添加P標簽,顯示上傳文件名 var p = "<p id=" + pid + " style='margin-left:140px;'> <label class='lblfile' id=" + lblid + " Title=" + fileid + ">" + filePath + "</label> "; p += "<img src='/images/刪除.png' style='width:1%;cursor:pointer;' onclick='DeleteFile(\"" + fileid + "\",\"" + pid + "\")'>"; p += "</p>"; $("#divShowFile").append(p); num++; } } } function DeleteFile(fileid, pid) { //將刪除的文件從全局變量FileData中刪除 FileData.delete(fileid); //刪除對應的P標簽 $("#" + pid).empty(); } $("#upload").click(function () { debugger; if ($(".lblfile").length == 0) { alert("請加入上傳文件"); } var formData = new FormData(); $(".lblfile").each(function () { formData.append("files", FileData.get($(this)[0].title)); }); $.ajax({ url: '/File/UploadFiles', type: 'POST', cache: false, data: formData, processData: false, contentType: false, success: function (data) { alert(data.result) } }).fail(function (res) { alert("系統錯誤") }); }); </script>
后台代碼:
此處是將上傳的批量File文件保存到Azure Blob,上傳文件到Azure Blob可以看我之前寫的博客 https://www.cnblogs.com/suflowers1700218/p/13606425.html
#region[文件上傳] public IActionResult Index() { return View(); } [HttpPost] public async Task<IActionResult> UploadFiles(IFormFile[] files) { try { for (int i = 0; i < files.Length; i++) {
//上傳文件到Azure Blob string oFileName = Path.GetFileName(files[i].FileName);//獲取文件名 string fileExtension = Path.GetExtension(oFileName).ToLower();//獲取文件擴展名 string AzureFilePath = $"{DateTime.Now.ToString("yyyyMMddHHmmssfff")}" + fileExtension; await AzureHelp.FileUploadAsync(AzureFilePath, files[i].OpenReadStream(), StorageConnectionstring, ContainerName); } return Json(new { Result = "Success", Message = "" }); } catch (Exception ex) { return Json(new { Result = "Failed", Message = ex.Message }); } } #endregion