# 閱讀技術文章_檔案上傳(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的鍵值對: ![](https://i.imgur.com/ChzsLcC.png) ```javascript= fd.set('name',"will"); ``` 只有一個 key为name的鍵值對: ![](https://i.imgur.com/DFrwN2b.png) 以上就是 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]); } ``` ![](https://i.imgur.com/82M0b8r.png) ```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); } ``` ![](https://i.imgur.com/uTRnpl8.png) ## 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對象