通过 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-Type
为 application/x-www-form-urlencoded
的方式发送。如果表单包含二进制数据,则必须使用 multipart/form-data
内容类型发送。
FormData
接口负责以这种方式对数据进行编码,在本篇文章的剩余部分,我们将简要介绍 FormData
。有关更多详细信息,请参见我们的使用 FormData 对象指南。
手动构建 FormData
对象
您可以通过调用对象append()
方法来填充 FormData
对象,该方法用于您要添加的每个字段,并传入字段的名称和值。对于文本字段,该值可以是字符串;对于二进制字段(包括File
对象),该值可以是Blob
。
在以下示例中,当用户单击按钮时,我们将数据作为表单提交发送。
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
头部:当我们将 FormData
对象传递到 fetch()
时,会自动设置正确的头部。
关联 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
请求发送。
另请参阅
学习路径
高级主题
- 通过 JavaScript 发送表单
- 如何构建自定义表单小部件
- 旧版浏览器中的 HTML 表单
- HTML 表单的高级样式
- 表单小部件属性兼容性表