透過 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 編碼的鍵/值對列表組成,並使用Content-Typeapplication/x-www-form-urlencoded 的方式傳送。如果表單包含二進位制資料,則必須使用 multipart/form-data 內容型別傳送。

FormData 介面負責以這種方式對資料進行編碼,在本篇文章的剩餘部分,我們將簡要介紹 FormData。有關更多詳細資訊,請參見我們的使用 FormData 物件指南。

手動構建 FormData 物件

您可以透過呼叫物件append() 方法來填充 FormData 物件,該方法用於您要新增的每個欄位,並傳入欄位的名稱和值。對於文字欄位,該值可以是字串;對於二進位制欄位(包括File 物件),該值可以是Blob

在以下示例中,當用戶單擊按鈕時,我們將資料作為表單提交發送。

js
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);
  1. 首先,我們構造一個新的、空的 FormData 物件。
  2. 接下來,我們呼叫 append() 兩次,向 FormData 物件新增兩個專案:一個文字欄位和一個檔案。
  3. 最後,我們使用 fetch() API 發出一個POST 請求,並將 FormData 物件設定為請求主體。

請注意,我們不需要設定Content-Type 頭部:當我們將 FormData 物件傳遞到 fetch() 時,會自動設定正確的頭部。

關聯 FormData 物件和 <form>

如果您提交的資料確實來自<form>,則可以透過將表單傳遞到 FormData 建構函式來填充 FormData 例項。

假設我們的 HTML 聲明瞭 <form> 元素

html
<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 程式碼如下

js
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 請求傳送。

另請參閱

學習路徑

高階主題