使用 FormData 对象

FormData 对象允许您编译一组键/值对,以便使用 FetchXMLHttpRequest API 进行发送。它主要用于发送表单数据,但也可以独立于表单使用,以传输键控数据。传输的数据格式与表单的 submit() 方法在表单编码类型设置为 multipart/form-data 时发送数据所使用的格式相同。

从头开始创建 FormData 对象

您可以自己构建 FormData 对象,实例化它,然后通过调用其 append() 方法来追加字段,如下所示:

js
const send = document.querySelector("#send");

send.addEventListener("click", async () => {
  const formData = new FormData();
  formData.append("username", "Groucho");
  formData.append("accountNum", 123456);

  // A file <input> element
  const avatar = document.querySelector("#avatar");
  formData.append("avatar", avatar.files[0]);

  // JavaScript file-like object
  const content = '<q id="a"><span id="b">hey!</span></q>';
  const blob = new Blob([content], { type: "text/xml" });
  formData.append("webmasterFile", blob);

  const response = await fetch("http://example.org/post", {
    method: "POST",
    body: formData,
  });
  console.log(await response.json());
});

注意: 字段 "avatar""webmasterFile" 都包含一个文件。分配给字段 "accountNum" 的数字会立即被 FormData.append() 方法转换为字符串(字段的值可以是 BlobFile 或字符串。如果值既不是 Blob 也不是 File,则该值将被转换为字符串)。

此示例构建了一个 FormData 实例,其中包含名为 "username""accountNum""avatar""webmasterFile" 的字段的值,然后使用 fetch() 发送表单数据。字段 "webmasterFile" 是一个 BlobBlob 对象代表一个文件类对象,包含不可变的原始数据。Blob 代表的数据不一定是 JavaScript 原生格式。 File 接口基于 Blob,继承了 Blob 的功能并对其进行了扩展,以支持用户系统上的文件。为了构建一个 Blob,您可以调用 Blob() 构造函数

从 HTML 表单检索 FormData 对象

要构造一个包含现有 <form> 数据的 FormData 对象,请在创建 FormData 对象时指定该表单元素。

注意: FormData 只会使用带有 name 属性的输入字段。

js
const formData = new FormData(someFormElement);

例如

js
const send = document.querySelector("#send");

send.addEventListener("click", async () => {
  // A <form> element
  const userInfo = document.querySelector("#user-info");
  const formData = new FormData(userInfo);

  const response = await fetch("http://example.org/post", {
    method: "POST",
    body: formData,
  });
  console.log(await response.json());
});

您也可以在从表单检索 FormData 对象并发送它之前,追加额外数据,如下所示:

js
const send = document.querySelector("#send");

send.addEventListener("click", async () => {
  const userInfo = document.querySelector("#user-info");
  const formData = new FormData(userInfo);
  formData.append("serialnumber", 12345);

  const response = await fetch("http://example.org/post", {
    method: "POST",
    body: formData,
  });
  console.log(await response.json());
});

这允许您在发送表单数据之前对其进行增强,以包含不一定是用户可编辑的额外信息。

使用 FormData 对象发送文件

您还可以使用 FormData 发送文件。在您的 <form> 中包含一个类型为 file<input> 元素。

html
<form enctype="multipart/form-data" method="post" name="fileinfo" id="fileinfo">
  <p>
    <label
      >Your email address:
      <input
        type="email"
        autocomplete="on"
        name="userid"
        placeholder="email"
        required
        size="32"
        maxlength="64" />
    </label>
  </p>
  <p>
    <label
      >Custom file label:
      <input type="text" name="file-label" size="12" maxlength="32" />
    </label>
  </p>
  <p>
    <label
      >File to stash:
      <input type="file" name="file" required />
    </label>
  </p>
  <p>
    <input type="submit" value="Stash the file!" />
  </p>
</form>

然后,您可以使用如下代码发送它:

js
const form = document.querySelector("#fileinfo");

form.addEventListener("submit", async (event) => {
  const formData = new FormData(form);

  formData.append("CustomField", "This is some extra data");

  const response = await fetch("stash.php", {
    method: "POST",
    body: formData,
  });
  event.preventDefault();
});

注意: 如果您传递表单的引用,则表单中指定的 请求 HTTP 方法将优先于 open() 调用中指定的方法。

警告: 当使用 FormData 使用 XMLHttpRequestFetch APImultipart/form-data 内容类型提交 POST 请求时(例如,上传文件和 Blobs 到服务器时),*请不要*显式设置请求的 Content-Type 标头。这样做会阻止浏览器能够设置 Content-Type 标头以及用于分隔请求正文中的表单字段的边界表达式。

您也可以直接将 FileBlob 追加到 FormData 对象,如下所示:

js
data.append("myfile", myBlob, "filename.txt");

当使用 append() 方法时,可以使用第三个可选参数在发送到服务器的 Content-Disposition 标头中传递文件名。当未指定文件名时(或参数不受支持时),将使用名称 "blob"。

使用 formdata 事件

formdata 事件比 FormData 对象出现得更晚,它在一个 HTMLFormElement 对象上触发,在表示表单数据条目的列表构造完成后。这发生在表单提交时,但也可以通过调用 FormData() 构造函数来触发。

这使得可以快速获得一个 FormData 对象作为对 formdata 事件触发的响应,而无需自己进行组装。

例如,在 JavaScript 中,我们可以引用一个表单:

js
const formElem = document.querySelector("form");

在我们的 submit 事件处理程序中,我们使用 preventDefault 来阻止默认的表单提交,然后调用 FormData() 构造函数来触发 formdata 事件。

js
formElem.addEventListener("submit", (e) => {
  // on form submission, prevent default
  e.preventDefault();

  // construct a FormData object, which fires the formdata event
  new FormData(formElem);
});

formdata 事件触发时,我们可以通过 FormDataEvent.formData 访问 FormData 对象,然后对其进行任何我们想要的操作(下面我们使用 XMLHttpRequest 将其发布到服务器)。

js
formElem.addEventListener("formdata", (e) => {
  console.log("formdata fired");

  // Get the form data from the event object
  const data = e.formData;
  for (const value of data.values()) {
    console.log(value);
  }

  // Submit the data via fetch()
  fetch("/formHandler", {
    method: "POST",
    body: data,
  });
});

注意事项

FormData 对象不包含禁用字段或禁用 fieldsets 的数据。

另见