透過 JavaScript 傳送表單
當用戶提交 HTML 表單時,例如透過點選 提交按鈕,瀏覽器會向指定的 HTTP 請求傳送表單中的資料。但與這種宣告式的方法不同,Web 應用有時會使用 JavaScript API,如 fetch(),以程式設計方式將資料傳送到期望表單提交的端點。本文將解釋為什麼這是一個重要的用例以及如何實現它。
為什麼使用 JavaScript 提交表單資料?
正如我們在關於 傳送表單資料 的文章中所述,標準的 HTML 表單提交會載入資料傳送到的 URL,這意味著瀏覽器視窗會進行整頁重新整理導航。
然而,許多 Web 應用,特別是 漸進式 Web 應用 和 單頁應用,使用 JavaScript API 從伺服器請求資料並更新頁面上相關部分,從而避免了整頁重新整理的開銷。
因此,當這些 Web 應用想要提交表單資料時,它們僅使用 HTML 表單來收集使用者輸入,而不是用於資料提交。當用戶嘗試傳送資料時,應用程式會接管控制權,並使用 JavaScript API(如 fetch())傳送資料。
JavaScript 表單提交的問題
如果 Web 應用傳送表單資料的伺服器端點在 Web 應用開發者的控制之下,那麼他們可以按任意方式傳送表單資料:例如,作為 JSON 物件。
但是,如果伺服器端點期望表單提交,Web 應用必須以特定方式編碼資料。例如,如果資料只是文字,它將由 URL 編碼的鍵/值對列表組成,並以 application/x-www-form-urlencoded 的 Content-Type 傳送。如果表單包含二進位制資料,則必須使用 multipart/form-data 內容型別傳送。
FormData 介面負責以這種方式編碼資料的過程,在本文的其餘部分,我們將快速介紹 FormData。有關更多詳細資訊,請參閱我們關於 使用 FormData 物件 的指南。
手動構建 FormData 物件
您可以透過為要新增的每個欄位呼叫物件的 append() 方法來填充 FormData 物件,傳入欄位的名稱和值。值可以是字串(用於文字欄位)或 Blob(用於二進位制欄位,包括 File 物件)。
在下面的示例中,當用戶點選按鈕時,我們將資料作為表單提交發送
async function sendData(data) {
// Construct a FormData instance
const formData = new FormData();
// Add a text field
formData.append("name", "Pomegranate");
// Add a file
const selection = await window.showOpenFilePicker();
if (selection.length > 0) {
const file = await selection[0].getFile();
formData.append("file", file);
}
try {
const response = await fetch("https://example.org/post", {
method: "POST",
// Set the FormData instance as the request body
body: formData,
});
console.log(await response.json());
} catch (e) {
console.error(e);
}
}
const send = document.querySelector("#send");
send.addEventListener("click", sendData);
-
我們首先構造一個新、空的
FormData物件。 -
接下來,我們呼叫兩次
append(),將兩個專案新增到FormData物件中:一個文字欄位和一個檔案。 -
最後,我們使用
fetch()API 發起一個POST請求,將FormData物件設定為請求體。
請注意,我們無需設定 Content-Type 標頭:當我們向 fetch() 傳遞 FormData 物件時,會自動設定正確的標頭。
關聯 FormData 物件和 <form>
如果您的資料實際上來自一個 <form>,您可以透過將表單傳遞給 FormData 建構函式來填充 FormData 例項。
假設我們的 HTML 聲明瞭一個 <form> 元素
<form id="userinfo">
<p>
<label for="username">Enter your name:</label>
<input type="text" id="username" name="username" value="Dominic" />
</p>
<p>
<label for="avatar">Select an avatar</label>
<input type="file" id="avatar" name="avatar" required />
</p>
<input type="submit" value="Submit" />
</form>
該表單包含一個文字輸入框、一個檔案輸入框和一個提交按鈕。
JavaScript 程式碼如下
const form = document.querySelector("#userinfo");
async function sendData() {
// Associate the FormData object with the form element
const formData = new FormData(form);
try {
const response = await fetch("https://example.org/post", {
method: "POST",
// Set the FormData instance as the request body
body: formData,
});
console.log(await response.json());
} catch (e) {
console.error(e);
}
}
// Take over form submission
form.addEventListener("submit", (event) => {
event.preventDefault();
sendData();
});
我們為表單元素添加了一個提交事件處理程式。它首先呼叫 preventDefault() 來阻止瀏覽器內建的表單提交,以便我們接管。然後我們呼叫 sendData(),它會檢索表單元素並將其傳遞給 FormData 建構函式。
之後,我們使用 fetch() 將 FormData 例項作為 HTTP POST 請求傳送。