使用 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,则该值将转换为字符串)。

此示例构建了一个包含名为 "username""accountnum""avatar""webmasterfile" 字段值的 FormData 实例,然后使用 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 中包含一个类型为 fileinput 元素

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="filelabel" 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() 调用中指定的 method。

警告: 当使用 FormDatamultipart/form-data 内容类型提交使用 XMLHttpRequestFetch API 的 POST 请求时(例如,将文件和 Blob 上传到服务器),不要在请求上显式设置 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 对象不包括来自被禁用的字段或被禁用的字段集的数据。

另请参阅