如何将 FormData(HTML5 对象)转换为 JSON

IT技术 javascript json form-data
2021-01-16 21:47:26

如何将条目从 HTML5FormData对象转换为 JSON?

该解决方案不应使用 jQuery。此外,它不应简单地序列化整个FormData对象,而应仅序列化其键/值条目。

6个回答

您也可以直接forEachFormData对象使用

var object = {};
formData.forEach(function(value, key){
    object[key] = value;
});
var json = JSON.stringify(object);

更新:

对于那些喜欢使用ES6 箭头函数的相同解决方案的人

var object = {};
formData.forEach((value, key) => object[key] = value);
var json = JSON.stringify(object);

更新 2:

对于那些想要支持多选列表或其他具有多个值的表单元素的人(因为关于这个问题的答案下面有很多评论,我将添加一个可能的解决方案)

var object = {};
formData.forEach((value, key) => {
    // Reflect.has in favor of: object.hasOwnProperty(key)
    if(!Reflect.has(object, key)){
        object[key] = value;
        return;
    }
    if(!Array.isArray(object[key])){
        object[key] = [object[key]];    
    }
    object[key].push(value);
});
var json = JSON.stringify(object);

这里有一个 Fiddle,通过一个简单的多选列表演示了这种方法的使用。

更新 3:

作为结束这里的人的旁注,如果将表单数据转换为 json 的目的是通过 XML HTTP 请求将其发送到服务器,您可以FormData直接发送对象而无需转换它。就这么简单:

var request = new XMLHttpRequest();
request.open("POST", "http://example.com/submitform.php");
request.send(formData);

使用FORMDATA对象上MDN以供参考

更新 4:

正如我的回答下面的评论之一中提到的,JSONstringify方法不适用于所有类型的对象。对于什么类型的支持的详细信息,我想指的描述部分的MDN文档JSON.stringify

在描述中还提到:

如果该值具有 toJSON() 方法,则它负责定义将序列化的数据。

这意味着您可以为您自己的toJSON序列化方法提供用于序列化自定义对象的逻辑。这样,您可以快速轻松地为更复杂的对象树构建序列化支持。

这不适用于多选表单元素,因为它们共享相同的键,您最终会覆盖仅返回最后一个选定元素的值
2021-03-15 21:47:26
formData 不是一个系列。你怎么能迭代?接受了答案,但遗漏了一些东西。
2021-04-02 21:47:26
除非需要多选等。答案JSON.stringify(Object.fromEntries(formData));要好得多
2021-04-08 21:47:26
@Sean 我通过将值转换为数组,给出了一个适用于多个值<SELECT MULTIPLE><INPUT type="checkbox">同名的答案
2021-04-09 21:47:26
正如@TomasPrado 的回答中提到的,确保您不需要对 IE11 的支持。
2021-04-10 21:47:26

2019年,这样的任务变得超级简单。

JSON.stringify(Object.fromEntries(formData));

Object.fromEntries:支持 Chrome 73+、Firefox 63+、Safari 12.1

来到这里发布这个,喜欢看这个帖子,看看这些年来答案是如何演变的
2021-03-14 21:47:26
最好使用 formData.entries: JSON.stringify(Object.fromEntries(formData.entries()));
2021-03-18 21:47:26
现在是 2020 年,这不处理<select multiple><input type="checkbox"> 😞 的多个选定值
2021-03-20 21:47:26
这在具有多个同名字段的表单上似乎无法正常工作。
2021-03-27 21:47:26
@Kohver,为什么更好?它会删除重复项吗?它解决了什么样的问题才能让它变得更好?
2021-04-05 21:47:26

这是一种以更具功能性的风格完成的方法,而无需使用库。

Array.from(formData.entries()).reduce((memo, pair) => ({
  ...memo,
  [pair[0]]: pair[1],
}), {});

例子:

document.getElementById('foobar').addEventListener('submit', (e) => {
  e.preventDefault();

  const formData = new FormData(e.target);
  const data = Array.from(formData.entries()).reduce((memo, pair) => ({
    ...memo,
    [pair[0]]: pair[1],
  }), {});
  document.getElementById('output').innerHTML = JSON.stringify(data);
});
<form id='foobar'>
  <input name='baz' />
  <input type='submit' />
</form>

<pre id='output'>Input some value and submit</pre>

我真的很喜欢这个答案,但仍然不处理多个项目。我发布了一个基于这个的新答案来处理这些情况。
2021-03-28 21:47:26

如果您有多个同名条目,例如,如果您使用<SELECT multiple>或有多个同名条目,则<INPUT type="checkbox">需要注意这一点并创建一个值数组。否则,您只能获得最后选择的值。

这是现代 ES6 变体:

function formToJSON( elem ) {
  let output = {};
  new FormData( elem ).forEach(
    ( value, key ) => {
      // Check if property already exist
      if ( Object.prototype.hasOwnProperty.call( output, key ) ) {
        let current = output[ key ];
        if ( !Array.isArray( current ) ) {
          // If it's not an array, convert it to an array.
          current = output[ key ] = [ current ];
        }
        current.push( value ); // Add the new value to the array.
      } else {
        output[ key ] = value;
      }
    }
  );
  return JSON.stringify( output );
}

稍微旧的代码(但 IE11 仍然不支持,因为它不支持ForEachentrieson FormData

function formToJSON( elem ) {
  var current, entries, item, key, output, value;
  output = {};
  entries = new FormData( elem ).entries();
  // Iterate over values, and assign to item.
  while ( item = entries.next().value )
    {
      // assign to variables to make the code more readable.
      key = item[0];
      value = item[1];
      // Check if key already exist
      if (Object.prototype.hasOwnProperty.call( output, key)) {
        current = output[ key ];
        if ( !Array.isArray( current ) ) {
          // If it's not an array, convert it to an array.
          current = output[ key ] = [ current ];
        }
        current.push( value ); // Add the new value to the array.
      } else {
        output[ key ] = value;
      }
    }
    return JSON.stringify( output );
  }
但是当复选框中只有 1 时,该值仍然是一个字符串,而不是一个数组。
2021-04-04 21:47:26
那是对的。由于您可以有多种类型的同名字段,因此我决定设置第一次出现的值,并且只有在找到多个值时才将其转换为数组。我不想先扫描表单以查找可能导致数组的字段名称。
2021-04-10 21:47:26

您可以通过使用FormData()对象来实现这一点这个 FormData 对象将使用表单的当前键/值填充,使用键的每个元素的 name 属性和它们提交的值的值。它还将对文件输入内容进行编码。

例子:

var myForm = document.getElementById('myForm');
myForm.addEventListener('submit', function(event)
{
    event.preventDefault();
    var formData = new FormData(myForm),
        result = {};

    for (var entry of formData.entries())
    {
        result[entry[0]] = entry[1];
    }
    result = JSON.stringify(result)
    console.log(result);

});
如果您使用 ES6,您还可以使 for of 语句更具表现力: for (const [key, value] of formData.entries())
2021-03-14 21:47:26
@Liam 你有没有用表单元素试过这个?让我知道为什么它不产生 JSON 对象?
2021-03-25 21:47:26
@Liam 创建对象后,他们可以使用 JSON.stringify(result)。我已经编辑了我的答案。请检查一下。并撤回反对票。
2021-03-25 21:47:26
这不会产生 json
2021-04-01 21:47:26
没有 json 对象这样的东西。Json 是一个字符串符号
2021-04-11 21:47:26