# 閱讀技術文章_檔案上傳(2)
---
###### tags: `檔案上傳` `技術文章` `javascript` `jQuery` `Ajax` `PHP`
有關FormData
[关于FormData对象的一些知识点(閱)](https://blog.csdn.net/weixin_37848710/article/details/82745827)
[HTML5 FormData用法详解以及文件上传实现过程讲解(閱)](https://www.php.cn/html5-tutorial-378573.html)
## 前筆記搬移
## 目錄
- FormData
- 使用FormData
- 操作方法-數據形式
## FormData
FormData類型其实是在 XMLHttpRequest 2级定義的,它是為序列化表以及創建與表单格式相同的數據(当然是用于XHR傳輸)提供便利。
FormData 對象的使用:
> ### 1. 用一些鍵值对来模拟一系列表单控件:即把form中所有表单元素的name 与value组装成一個queryString
>
>### 2. 异步上传二进制文件。
## XMLHttpRequest 2級
XMLHttpRequest 是一个瀏覽器接口,通過它,我们可以使得 Javascript 进行 HTTP (S) 通信。
XMLHttpRequest 在现在瀏覽器中是一种常用的前後台交互數據的方式。2008年 2 月,XMLHttpRequest Level 2 草案提出来了,相对于上一代,它有一些新的特性,其中 FormData 就是 XMLHttpRequest Level 2 新增的一個對象,利用它来提交表單、模拟表單提交,当然最大的優勢就是可以上傳二进制文件。下面就具体介绍一下如何利用 FormData 来上传文件。
## 使用FormData
创建一个formData对象實例有几種方式
1. 創建一個空对象 實例
```javascript=
var formData = new FormData();
```
這時可以调用append()方法来添加数据
2. 使用已有的表单来初始化一个对象實例
```javascript=
<form id="myForm" action="" method="post">
<input type="text" name="name">名字
<input type="password" name="psw">密码
<input type="submit" value="提交">
</form>
```
假如现在页面已经有一个表單
我们可以使用这个表單元素作為初始化参数,来實例化一个formData对象
```javascript=
// 獲取页面已有的一个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里面存储的數據形式
>***一對key/value组成一条數據***
>
>***key是唯一的,一个key可能对应多个value。***
如果是使用 表單初始化(new FormData(myform) )
每一个表单字段对应一条數據,它们的HTML name屬性即为key值,它们value屬性对应value值。
| | key | value | |
| --- | --- | ----- | --- |
| | k1 | [v1,v2,v3] | |
| | k2 | v4 | |
## 操作方法-獲取值get() 和 getAll()
接收一个参数,表示需要查找的 key 的名称
***返回第一个该 key 对应的 value 值。如果有多个相同的 key, 而且要返回所有的这个 key 对应的 value 值。
可以通过get(key)/getAll(key)來獲取对应的value***
```javascript=
formData.get("name"); // 獲取key为name的第一个值
formData.getAll("name"); // 返回一个数组,获取key为name的所有值
fd.append('name','will');
console.log(fd.get('name')); // sean
fd.append('name','will');
console.log(fd.getAll('name')); // ["sean", "will"]
```
## 操作方法-添加数据append()
我们可以通过append(key, value)来添加数据,如果指定的key不存在则会新增一条数据,如果key存在,则添加到数据的末尾
```javascript=
formData.append("k1", "v1");
formData.append("k1", "v2");
formData.append("k1", "v1");
formData.get("k1"); // "v1"
formData.getAll("k1"); // ["v1","v2","v1"]
```
formData是 FormData 對象,可以新建的空的对象,也可以是已经包含 form 表單或其他鍵值對。
## 操作方法-設置修改數據set()
设置对应的鍵 key 对应的值 value(s)
```javascript=
fd.set('key1',"value1");
fd.set('key2',"value2");
```
看起来跟append() 方法有点類似,这兩者的区别就是,
当指定的 key 值存在时,append()方法是將新增的添加的所以的鍵值对最后,而set()方法将会覆蓋前面的设置的鍵值对。还是通过實例來對比,我们在前面的 form 的基础上 append() 或 set() 新的鍵值对:
```javascript=
fd.append('name',"will");
```
有两個 key為name的鍵值對:

```javascript=
fd.set('name',"will");
```
只有一個 key为name的鍵值對:

以上就是 append() 和 set() 的區别。如果設置的key值不存在,那麼兩者的效果是一样的。
操作方法-判断是否含該數據has()
該方法也接收一個參數,同樣是 key 的名稱,返回一個Boolean 值, 用來判斷FormData 對像是否含有該 key。以上面的form為例:
```javascript=
console.log(fd.has('name')); // true
console.log(fd.has('Name')); // false
```
## 操作方法-刪除數據
接收一個參數,表示你要刪除的 key 值的名字,如果有多個相同 key 值,會一併刪除:
```javascript=
fd.append('name','will');
fd.delete('name');
```
form 中的 name 信息以及通過append() 新增的name 的信息都被刪除了。
## 操作方法-遍歷entries()
有遍歷 key 的迭代器,也有遍歷 value 的迭代器,為何不搞一個兩者一起的呢! entries()就是返回一個包含鍵值對的迭代器:
```javascript=
for(var pair of fd.entries()) {
console.log(pair[0]+ ', '+ pair[1]);
}
```

```javascript=
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:fase, value:["k1", "v2"]}
i.next(); // {done:fase, value:["k2", "v1"]}
i.next(); // {done:true, value:undefined}
```
可以看到返回迭代器的規則
1. 每調用一次next()返回一條數據,數據的順序由添加的順序決定
2. 返回的是一個對象,當其done屬性為true時,說明已經遍歷完所有的數據,這個也可以作為判斷的依據
3. 返回的對象的value屬性以數組形式存儲了一對key/value,數組下標0為key,下標1為value,如果一個key值對應多個value,會變成多對key/value返回
## values()
通過values()方法只獲取value值
```javascript=
for (var value of fd.values()) {
console.log(value);
}
```

## keys()
不需要接收參數,返回一個迭代器,通過這個迭代器,我們可以遍歷FormData 對像中所有的 key。以上面的form為例:
```javascript=
for (var key of fd.keys()) {
console.log(key);
}
```
## 發送數據
我們可以通過xhr來發送數據
```javascript=
var xhr = new XMLHttpRequest();
xhr.open("post","login");
// 監聽上传进度
xhr.upload.onprogress = function (ev) {
// 事件对象
// console.log(ev);
var percent = (ev.loaded / ev.total) * 100 + '%';
console.log(percent);
progress.style.width = percent;
}
xhr.send(formData);
xhr.onreadystatechange = function () {
if(xhr.readyState == 4 && xhr.status == 200) {
//
}
}
```
這種方式可以來實現文件的異步上傳。
使用jQuery+Ajax進行表單提交至後台處理
```javascript=
$.ajax({
url: 'formController/save',
type: 'POST',
data: formdata, // 上传formdata封装的数据
dataType: 'JSON',
cache: false, // 不缓存
processData: false, // jQuery不要去处理发送的数据
contentType: false, // jQuery不要去设置Content-Type请求頭
success:function (data) { //成功回调
console.log(data);
}
});
```
參數 new FormData的參數是一個DOM對象,而非jQuery對象