W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
這一章是關(guān)于發(fā)送 HTML 表單的:帶有或不帶文件,帶有其他字段等。
FormData 對(duì)象可以提供幫助。你可能已經(jīng)猜到了,它是表示 HTML 表單數(shù)據(jù)的對(duì)象。
構(gòu)造函數(shù)是:
let formData = new FormData([form]);
如果提供了 HTML form
元素,它會(huì)自動(dòng)捕獲 form
元素字段。
FormData
的特殊之處在于網(wǎng)絡(luò)方法(network methods),例如 fetch
可以接受一個(gè) FormData
對(duì)象作為 body。它會(huì)被編碼并發(fā)送出去,帶有 Content-Type: multipart/form-data
。
從服務(wù)器角度來看,它就像是一個(gè)普通的表單提交。
我們先來發(fā)送一個(gè)簡(jiǎn)單的表單。
正如你所看到的,它幾乎就是一行代碼:
<form id="formElem">
<input type="text" name="name" value="John">
<input type="text" name="surname" value="Smith">
<input type="submit">
</form>
<script>
formElem.onsubmit = async (e) => {
e.preventDefault();
let response = await fetch('/article/formdata/post/user', {
method: 'POST',
body: new FormData(formElem)
});
let result = await response.json();
alert(result.message);
};
</script>
在這個(gè)示例中,沒有將服務(wù)器代碼展示出來,因?yàn)樗隽宋覀儺?dāng)前的學(xué)習(xí)范圍。服務(wù)器接受 POST 請(qǐng)求并回應(yīng) “User saved”。
我們可以使用以下方法修改 ?FormData
? 中的字段:
formData.append(name, value)
? —— 添加具有給定 ?name
? 和 ?value
? 的表單字段,formData.append(name, blob, fileName)
? —— 添加一個(gè)字段,就像它是 ?<input type="file">
?,第三個(gè)參數(shù) ?fileName
? 設(shè)置文件名(而不是表單字段名),因?yàn)樗怯脩粑募到y(tǒng)中文件的名稱,formData.delete(name)
? —— 移除帶有給定 ?name
? 的字段,formData.get(name)
? —— 獲取帶有給定 ?name
? 的字段值,formData.has(name)
? —— 如果存在帶有給定 ?name
? 的字段,則返回 ?true
?,否則返回 ?false
?。從技術(shù)上來講,一個(gè)表單可以包含多個(gè)具有相同 name
的字段,因此,多次調(diào)用 append
將會(huì)添加多個(gè)具有相同名稱的字段。
還有一個(gè) set
方法,語(yǔ)法與 append
相同。不同之處在于 .set
移除所有具有給定 name
的字段,然后附加一個(gè)新字段。因此,它確保了只有一個(gè)具有這種 name
的字段,其他的和 append
一樣:
formData.set(name, value)
?,formData.set(name, blob, fileName)
?。我們也可以使用 for..of
循環(huán)迭代 formData 字段:
let formData = new FormData();
formData.append('key1', 'value1');
formData.append('key2', 'value2');
// 列出 key/value 對(duì)
for(let [name, value] of formData) {
alert(`${name} = ${value}`); // key1 = value1,然后是 key2 = value2
}
表單始終以 Content-Type: multipart/form-data
來發(fā)送數(shù)據(jù),這個(gè)編碼允許發(fā)送文件。因此 <input type="file">
字段也能被發(fā)送,類似于普通的表單提交。
這是具有這種形式的示例:
<form id="formElem">
<input type="text" name="firstName" value="John">
Picture: <input type="file" name="picture" accept="image/*">
<input type="submit">
</form>
<script>
formElem.onsubmit = async (e) => {
e.preventDefault();
let response = await fetch('/article/formdata/post/user-avatar', {
method: 'POST',
body: new FormData(formElem)
});
let result = await response.json();
alert(result.message);
};
</script>
正如我們?cè)?nbsp;Fetch 一章中所看到的,以 Blob
發(fā)送一個(gè)動(dòng)態(tài)生成的二進(jìn)制數(shù)據(jù),例如圖片,是很簡(jiǎn)單的。我們可以直接將其作為 fetch
參數(shù)的 body
。
但在實(shí)際中,通常更方便的發(fā)送圖片的方式不是單獨(dú)發(fā)送,而是將其作為表單的一部分,并帶有附加字段(例如 “name” 和其他 metadata)一起發(fā)送。
并且,服務(wù)器通常更適合接收多部分編碼的表單(multipart-encoded form),而不是原始的二進(jìn)制數(shù)據(jù)。
下面這個(gè)例子使用 FormData
將一個(gè)來自 <canvas>
的圖片和一些其他字段一起作為一個(gè)表單提交:
<body style="margin:0">
<canvas id="canvasElem" width="100" height="80" style="border:1px solid"></canvas>
<input type="button" value="Submit" onclick="submit()">
<script>
canvasElem.onmousemove = function(e) {
let ctx = canvasElem.getContext('2d');
ctx.lineTo(e.clientX, e.clientY);
ctx.stroke();
};
async function submit() {
let imageBlob = await new Promise(resolve => canvasElem.toBlob(resolve, 'image/png'));
let formData = new FormData();
formData.append("firstName", "John");
formData.append("image", imageBlob, "image.png");
let response = await fetch('/article/formdata/post/image-form', {
method: 'POST',
body: formData
});
let result = await response.json();
alert(result.message);
}
</script>
</body>
請(qǐng)注意圖片 Blob
是如何添加的:
formData.append("image", imageBlob, "image.png");
就像表單中有 <input type="file" name="image">
一樣,用戶從他們的文件系統(tǒng)中使用數(shù)據(jù) imageBlob
(第二個(gè)參數(shù))提交了一個(gè)名為 image.png
(第三個(gè)參數(shù))的文件。
服務(wù)器讀取表單數(shù)據(jù)和文件,就好像它是常規(guī)的表單提交一樣。
FormData 對(duì)象用于捕獲 HTML 表單,并使用 fetch
或其他網(wǎng)絡(luò)方法提交。
我們可以從 HTML 表單創(chuàng)建 new FormData(form)
,也可以創(chuàng)建一個(gè)完全沒有表單的對(duì)象,然后使用以下方法附加字段:
formData.append(name, value)
?formData.append(name, blob, fileName)
?formData.set(name, value)
?formData.set(name, blob, fileName)
?讓我們?cè)谶@里注意兩個(gè)特點(diǎn):
set
? 方法會(huì)移除具有相同名稱(name)的字段,而 ?append
? 不會(huì)。<input type="file">
? 從用戶文件系統(tǒng)中獲取的。其他方法是:
formData.delete(name)
?formData.get(name)
?formData.has(name)
?這就是它的全貌!
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: