如何将 FormData(HTML5 对象)转换为 JSON
How to convert FormData (HTML5 object) to JSON
如何将条目从 HTML5 FormData
对象转换为 JSON?
解决方案不应使用 jQuery。此外,它不应简单地序列化整个 FormData
对象,而应仅序列化其 key/value 条目。
您可以使用 FormData() 对象来实现。此 FormData 对象将使用表单的当前 keys/values 填充,使用每个元素的名称 属性 作为键,并使用它们提交的值作为值。它还会对文件输入内容进行编码。
示例:
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);
});
简单易用的功能
function FormDataToJSON(FormElement){
var formData = new FormData(FormElement);
var ConvertedJSON= {};
for (const [key, value] of formData.entries())
{
ConvertedJSON[key] = value;
}
return ConvertedJSON
}
示例用法
var ReceivedJSON = FormDataToJSON(document.getElementById('FormId');)
在这段代码中,我使用 for
循环创建了空 JSON 变量 我在每个 Itration 中使用了从 formData 对象到 JSON 键的 key
s。
您在我的 JS 库中找到此代码 GitHub 如果需要改进,请给我建议我已将代码放在这里 https://github.com/alijamal14/Utilities/blob/master/Utilities.js
您也可以直接在 FormData
对象上使用 forEach
:
var object = {};
formData.forEach(function(value, key){
object[key] = value;
});
var json = JSON.stringify(object);
更新:
对于那些喜欢与 ES6 arrow functions 相同解决方案的人:
var object = {};
formData.forEach((value, key) => object[key] = value);
var json = JSON.stringify(object);
更新 2:
对于那些想要支持多 select 列表或其他具有多个值的表单元素的人 (因为关于这个问题的答案下面有很多评论,我将添加一个可能的解决方案):
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);
Here a Fiddle 演示如何使用简单的多 select 列表。
更新 3:
作为那些在此处结束的人的旁注,如果将表单数据转换为 json 的目的是通过 XML HTTP 请求将其发送到服务器,您可以发送FormData
直接对象而不转换它。就这么简单:
var request = new XMLHttpRequest();
request.open("POST", "http://example.com/submitform.php");
request.send(formData);
见also Using FormData Objects on MDN for reference:
更新 4:
正如在我的回答下面的评论之一中提到的,JSON stringify
方法并非对所有类型的对象都适用。有关支持哪些类型的更多信息,我想参考 the Description section in the MDN documentation of JSON.stringify
.
描述中还提到:
If the value has a toJSON() method, it's responsible to define what data will be serialized.
这意味着您可以提供自己的 toJSON
序列化方法和序列化自定义对象的逻辑。这样您就可以快速轻松地为更复杂的对象树构建序列化支持。
如果您使用的是 lodash,可以通过 fromPairs
简洁地完成
import {fromPairs} from 'lodash';
const object = fromPairs(Array.from(formData.entries()));
这是一种无需使用库即可以更实用的方式完成此操作的方法。
Array.from(formData.entries()).reduce((memo, [key, value]) => ({
...memo,
[key]: value,
}), {});
示例:
document.getElementById('foobar').addEventListener('submit', (e) => {
e.preventDefault();
const formData = new FormData(e.target);
const data = Array.from(formData.entries()).reduce((memo, [key, value]) => ({
...memo,
[key]: value,
}), {});
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>
如果您有多个具有相同名称的条目,例如,如果您使用 <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 支持,因为它不支持 FormData
上的 ForEach
或 entries
)
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 );
}
你可以试试这个
formDataToJSON($('#form_example'));
# Create a function to convert the serialize and convert the form data
# to JSON
# @param : $('#form_example');
# @return a JSON Stringify
function formDataToJSON(form) {
let obj = {};
let formData = form.serialize();
let formArray = formData.split("&");
for (inputData of formArray){
let dataTmp = inputData.split('=');
obj[dataTmp[0]] = dataTmp[1];
}
return JSON.stringify(obj);
}
这个 post 已经一岁了...但是,我真的非常喜欢 ES6 @dzuc 的回答。然而,由于无法处理多个选择或复选框,它是不完整的。这已经指出并提供了代码解决方案。我发现它们很重而且没有优化。所以我基于@dzuc写了两个版本来处理这些情况:
- 对于 ASP 样式表单,其中多个项目名称可以简单重复。
let r=Array.from(fd).reduce(
(o , [k,v]) => (
(!o[k])
? {...o , [k] : v}
: {...o , [k] : [...o[k] , v]}
)
,{}
);
let obj=JSON.stringify(r);
一行Hotshot版本:
Array.from(fd).reduce((o,[k,v])=>((!o[k])?{...o,[k]:v}:{...o,[k]:[...o[k],v]}),{});
- 对于 PHP 样式表单,其中多个项目名称必须具有
[]
后缀。
let r=Array.from(fd).reduce(
(o , [k,v]) => (
(k.split('[').length>1)
? (k=k.split('[')[0]
, (!o[k])
? {...o , [k] : [v]}
: {...o , [k] : [...o[k] , v ]}
)
: {...o , [k] : v}
)
,{}
);
let obj=JSON.stringify(r);
一行Hotshot版本:
Array.from(fd).reduce((o,[k,v])=>((k.split('[').length>1)?(k=k.split('[')[0],(!o[k])?{...o,[k]:[v]}:{...o,[k]:[...o[k],v]}):{...o,[k]:v}),{});
- 支持多级数组的 PHP 形式的扩展。
自从上次写了前面的第二种情况,在工作中遇到了PHP表单多级checkbox的情况。我写了一个新案例来支持以前的案例和这个案例。我创建了一个片段来更好地展示这个案例,结果显示在这个演示的控制台上,根据你的需要修改它。试图在不影响性能的情况下尽我所能优化它,但是,它损害了一些人类的可读性。它利用了数组是对象并且指向数组的变量被保留为引用。没有这个能人,请客。
let nosubmit = (e) => {
e.preventDefault();
const f = Array.from(new FormData(e.target));
const obj = f.reduce((o, [k, v]) => {
let a = v,
b, i,
m = k.split('['),
n = m[0],
l = m.length;
if (l > 1) {
a = b = o[n] || [];
for (i = 1; i < l; i++) {
m[i] = (m[i].split(']')[0] || b.length) * 1;
b = b[m[i]] = ((i + 1) == l) ? v : b[m[i]] || [];
}
}
return { ...o, [n]: a };
}, {});
console.log(obj);
}
document.querySelector('#theform').addEventListener('submit', nosubmit, {capture: true});
<h1>Multilevel Form</h1>
<form action="#" method="POST" enctype="multipart/form-data" id="theform">
<input type="hidden" name="_id" value="93242" />
<input type="hidden" name="_fid" value="45c0ec96929bc0d39a904ab5c7af70ef" />
<label>Select:
<select name="uselect">
<option value="A">A</option>
<option value="B">B</option>
<option value="C">C</option>
</select>
</label>
<br /><br />
<label>Checkboxes one level:<br/>
<input name="c1[]" type="checkbox" checked value="1"/>v1
<input name="c1[]" type="checkbox" checked value="2"/>v2
<input name="c1[]" type="checkbox" checked value="3"/>v3
</label>
<br /><br />
<label>Checkboxes two levels:<br/>
<input name="c2[0][]" type="checkbox" checked value="4"/>0 v4
<input name="c2[0][]" type="checkbox" checked value="5"/>0 v5
<input name="c2[0][]" type="checkbox" checked value="6"/>0 v6
<br/>
<input name="c2[1][]" type="checkbox" checked value="7"/>1 v7
<input name="c2[1][]" type="checkbox" checked value="8"/>1 v8
<input name="c2[1][]" type="checkbox" checked value="9"/>1 v9
</label>
<br /><br />
<label>Radios:
<input type="radio" name="uradio" value="yes">YES
<input type="radio" name="uradio" checked value="no">NO
</label>
<br /><br />
<input type="submit" value="Submit" />
</form>
尽管@dzuc 的答案已经非常好,但您可以使用数组解构(在现代浏览器或 Babel 中可用)使其更加优雅:
// original version from @dzuc
const data = Array.from(formData.entries())
.reduce((memo, pair) => ({
...memo,
[pair[0]: pair[1],
}), {})
// with array destructuring
const data = Array.from(formData.entries())
.reduce((memo,[key, value]) => ({
...memo,
[key]: value,
}), {})
如果以下项目满足您的需求,那么您很幸运:
- 您想将像
[['key','value1'], ['key2','value2']
这样的数组(就像 FormData 给你的那样)转换成像 {key1: 'value1', key2: 'value2'}
这样的键->值对象,然后将它转换成 JSON字符串.
- 您的目标是 browsers/devices 使用最新的 ES6 解释器或使用 babel 之类的工具进行编译。
- 您想要完成此任务的最简单方法。
这是您需要的代码:
const data = new FormData(document.querySelector('form'));
const json = JSON.stringify(Array.from(data).reduce((o,[k,v])=>(o[k]=v,o),{}));
希望这对某人有所帮助。
辱骂单行!
Array.from(fd).reduce((obj, [k, v]) => ({...obj, [k]: v}), {});
今天我了解到 firefox 支持对象传播和数组解构!
为我工作
var myForm = document.getElementById("form");
var formData = new FormData(myForm),
obj = {};
for (var entry of formData.entries()){
obj[entry[0]] = entry[1];
}
console.log(obj);
2019年,这种任务变得超级简单。
JSON.stringify(Object.fromEntries(formData));
Object.fromEntries
:支持 Chrome 73+、Firefox 63+、Safari 12.1
如评论中所述,请注意:FormData
可以包含具有相同键的多个值(例如具有相同名称的复选框)。 Object.fromEntries()
丢弃重复项,只保留最后一个。
在我的例子中,表单数据是数据,fire base 需要一个对象,但数据包含对象以及所有其他东西,所以我试过 data.value 它有效!!!
我来晚了。但是,我做了一个简单的方法来检查输入类型="checkbox"
var formData = new FormData($form.get(0));
var objectData = {};
formData.forEach(function (value, key) {
var updatedValue = value;
if ($('input[name="' + key + '"]').attr("type") === "checkbox" && $('input[name="' + key + '"]').is(":checked")) {
updatedValue = true; // we don't set false due to it is by default on HTML
}
objectData[key] = updatedValue;
});
var jsonData = JSON.stringify(objectData);
我希望这对其他人有帮助。
如果您需要支持序列化嵌套字段,类似于PHP处理表单字段的方式,您可以使用以下函数
function update(data, keys, value) {
if (keys.length === 0) {
// Leaf node
return value;
}
let key = keys.shift();
if (!key) {
data = data || [];
if (Array.isArray(data)) {
key = data.length;
}
}
// Try converting key to a numeric value
let index = +key;
if (!isNaN(index)) {
// We have a numeric index, make data a numeric array
// This will not work if this is a associative array
// with numeric keys
data = data || [];
key = index;
}
// If none of the above matched, we have an associative array
data = data || {};
let val = update(data[key], keys, value);
data[key] = val;
return data;
}
function serializeForm(form) {
return Array.from((new FormData(form)).entries())
.reduce((data, [field, value]) => {
let [_, prefix, keys] = field.match(/^([^\[]+)((?:\[[^\]]*\])*)/);
if (keys) {
keys = Array.from(keys.matchAll(/\[([^\]]*)\]/g), m => m[1]);
value = update(data[prefix], keys, value);
}
data[prefix] = value;
return data;
}, {});
}
document.getElementById('output').textContent = JSON.stringify(serializeForm(document.getElementById('form')), null, 2);
<form id="form">
<input name="field1" value="Field 1">
<input name="field2[]" value="Field 21">
<input name="field2[]" value="Field 22">
<input name="field3[a]" value="Field 3a">
<input name="field3[b]" value="Field 3b">
<input name="field3[c]" value="Field 3c">
<input name="field4[x][a]" value="Field xa">
<input name="field4[x][b]" value="Field xb">
<input name="field4[x][c]" value="Field xc">
<input name="field4[y][a]" value="Field ya">
<input name="field5[z][0]" value="Field z0">
<input name="field5[z][]" value="Field z1">
<input name="field6.z" value="Field 6Z0">
<input name="field6.z" value="Field 6Z1">
</form>
<h2>Output</h2>
<pre id="output">
</pre>
到目前为止,我还没有看到有人提到 FormData.getAll 方法。
除了从 FormData 对象中返回与给定键关联的所有值外,使用此处其他人指定的 Object.fromEntries 方法变得非常简单。
var formData = new FormData(document.forms[0])
var obj = Object.fromEntries(
Array.from(formData.keys()).map(key => [
key, formData.getAll(key).length > 1 ?
formData.getAll(key) : formData.get(key)
])
)
实际片段
var formData = new FormData(document.forms[0])
var obj = Object.fromEntries(Array.from(formData.keys()).map(key => [key, formData.getAll(key).length > 1 ? formData.getAll(key) : formData.get(key)]))
document.write(`<pre>${JSON.stringify(obj)}</pre>`)
<form action="#">
<input name="name" value="Robinson" />
<input name="items" value="Vin" />
<input name="items" value="Fromage" />
<select name="animals" multiple id="animals">
<option value="tiger" selected>Tigre</option>
<option value="turtle" selected>Tortue</option>
<option value="monkey">Singe</option>
</select>
</form>
我认为这是从 formData
FormData 对象获得所需结果的最简单方法:
const jsonData = {};
for(const [key, value] of formData) {
jsonData[key] = value;
}
这对我有用。
Click here查看详情代码
let formToJson = function(){
let form = new FormData($("form#formData")[0]);
//console.log(form);
let jsonData = Object.fromEntries(form.entries());
//console.log(jsonData);
$("#jsonData").html(JSON.stringify(jsonData));
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<div class="">
<form action="#" method="post" id="formData">
<input type="text" name="fName" id="fName" value="Mad"><br>
<input type="text" name="lName" id="lName" value="Coder"><br>
<input type="button" onclick="formToJson()" value="Boom Yeah">
</form>
</div>
<div id="jsonData">
</div>
</body>
</html>
如果你想要 json 字符串:
var jsonStr = JSON.stringify($('#formId').serializeObject());
如果你想要一个 json 对象
var jsonObj = JSON.parse(JSON.stringify($('#formId').serializeObject()));
中所述使用toJSON
If the value has a toJSON()
method, it's responsible to define what data will be serialized.
这是一个小窍门。
var fd = new FormData(document.forms[0]);
fd.toJSON = function() {
const o = {};
this.forEach((v, k) => {
v = this.getAll(k);
o[k] = v.length == 1 ? v[0] : (v.length >= 1 ? v : null);
});
return o;
};
document.write(`<pre>${JSON.stringify(fd)}</pre>`)
<form action="#">
<input name="name" value="Robinson" />
<input name="items" value="Vin" />
<input name="items" value="Fromage" />
<select name="animals" multiple id="animals">
<option value="tiger" selected>Tigre</option>
<option value="turtle" selected>Tortue</option>
<option value="monkey">Singe</option>
</select>
</form>
这解决了我的问题,这是一个对象
const formDataObject = (formData) => {
for (const key in formData) {
if (formData[key].startsWith('{') || formData[key].startsWith('[')) {
try {
formData[key] = JSON.parse(formData[key]);
console.log("key is :", key, "form data is :", formData[key]);
} catch (error) {
console.log("error :", key);
}
}
}
console.log("object", formData)
}
另一种适用于 select 多个或具有相同名称属性的输入的方法:
function form_to_json() {
const form_data = new FormData(document.querySelector('form'))
const uniqueKeys = [...new Set(form_data.keys())]
const obj = {}
uniqueKeys.forEach((value, key) => {
obj[value] = (form_data.getAll(value).length > 1) ? form_data.getAll(value) : form_data.get(value)
})
const json = JSON.stringify(obj)
alert(json)
}
<form>
<input type="text" name="name" value="Cesar"></br>
<select name="cars" id="cars" multiple>
<option value="volvo" selected>Volvo</option>
<option value="saab" selected>Saab</option>
</select>
<input type="button" onclick="form_to_json()" value="Ok">
</form>
我知道已经晚了,但这是解决方案;
new URLSearchParams(new FormData(formElement)).toString()
现在,可以将其作为正文发送。遗憾的是,它不是 JSON。
这是一个将 formData 对象转换为 JSON-string 的函数。
- 适用于多个条目和嵌套数组。
- 适用于编号和命名输入名称数组。
例如,您可以有以下表单字段:
<select name="select[]" multiple></select>
<input name="check[a][0][]" type="checkbox" value="test"/>
用法:
let json = form2json(formData);
函数:
function form2json(data) {
let method = function (object,pair) {
let keys = pair[0].replace(/\]/g,'').split('[');
let key = keys[0];
let value = pair[1];
if (keys.length > 1) {
let i,x,segment;
let last = value;
let type = isNaN(keys[1]) ? {} : [];
value = segment = object[key] || type;
for (i = 1; i < keys.length; i++) {
x = keys[i];
if (i == keys.length-1) {
if (Array.isArray(segment)) {
segment.push(last);
} else {
segment[x] = last;
}
} else if (segment[x] == undefined) {
segment[x] = isNaN(keys[i+1]) ? {} : [];
}
segment = segment[x];
}
}
object[key] = value;
return object;
}
let object = Array.from(data).reduce(method,{});
return JSON.stringify(object);
}
多年后在 vanillaJs (es6) 中
let body = new FormData()
body.set('key1', 'value AA')
body.set('key2', 'value BB')
let data = [...body.keys()].reduce( (acc, key, idx) => {
acc[key] = body.get(key)
return acc
} , {} )
console.log(JSON.stringify(data)) // {key1: 'value AA', key2: 'value BB'}
这是一种包含处理多个值的简单方法的方法。如果键以 []
结尾,它会将值组合到一个数组中(就像在旧的 php 约定中一样),并从键中删除 []
:
function formDataToJson(f) {
return Object.fromEntries(Array.from(f.keys(), k =>
k.endsWith('[]') ? [k.slice(0, -2), f.getAll(k)] : [k, f.get(k)]));
}
例如,如果您有:
const f = new FormData();
f.append("a", "1");
f.append("a", "2");
f.append("b[]", "3");
f.append("b[]", "4");
formDataToJson(f) // --> produces {a: "1", b: ["3","4"]}
如何将条目从 HTML5 FormData
对象转换为 JSON?
解决方案不应使用 jQuery。此外,它不应简单地序列化整个 FormData
对象,而应仅序列化其 key/value 条目。
您可以使用 FormData() 对象来实现。此 FormData 对象将使用表单的当前 keys/values 填充,使用每个元素的名称 属性 作为键,并使用它们提交的值作为值。它还会对文件输入内容进行编码。
示例:
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);
});
简单易用的功能
function FormDataToJSON(FormElement){
var formData = new FormData(FormElement);
var ConvertedJSON= {};
for (const [key, value] of formData.entries())
{
ConvertedJSON[key] = value;
}
return ConvertedJSON
}
示例用法
var ReceivedJSON = FormDataToJSON(document.getElementById('FormId');)
在这段代码中,我使用 for
循环创建了空 JSON 变量 我在每个 Itration 中使用了从 formData 对象到 JSON 键的 key
s。
您在我的 JS 库中找到此代码 GitHub 如果需要改进,请给我建议我已将代码放在这里 https://github.com/alijamal14/Utilities/blob/master/Utilities.js
您也可以直接在 FormData
对象上使用 forEach
:
var object = {};
formData.forEach(function(value, key){
object[key] = value;
});
var json = JSON.stringify(object);
更新:
对于那些喜欢与 ES6 arrow functions 相同解决方案的人:
var object = {};
formData.forEach((value, key) => object[key] = value);
var json = JSON.stringify(object);
更新 2:
对于那些想要支持多 select 列表或其他具有多个值的表单元素的人 (因为关于这个问题的答案下面有很多评论,我将添加一个可能的解决方案):
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);
Here a Fiddle 演示如何使用简单的多 select 列表。
更新 3:
作为那些在此处结束的人的旁注,如果将表单数据转换为 json 的目的是通过 XML HTTP 请求将其发送到服务器,您可以发送FormData
直接对象而不转换它。就这么简单:
var request = new XMLHttpRequest();
request.open("POST", "http://example.com/submitform.php");
request.send(formData);
见also Using FormData Objects on MDN for reference:
更新 4:
正如在我的回答下面的评论之一中提到的,JSON stringify
方法并非对所有类型的对象都适用。有关支持哪些类型的更多信息,我想参考 the Description section in the MDN documentation of JSON.stringify
.
描述中还提到:
If the value has a toJSON() method, it's responsible to define what data will be serialized.
这意味着您可以提供自己的 toJSON
序列化方法和序列化自定义对象的逻辑。这样您就可以快速轻松地为更复杂的对象树构建序列化支持。
如果您使用的是 lodash,可以通过 fromPairs
import {fromPairs} from 'lodash';
const object = fromPairs(Array.from(formData.entries()));
这是一种无需使用库即可以更实用的方式完成此操作的方法。
Array.from(formData.entries()).reduce((memo, [key, value]) => ({
...memo,
[key]: value,
}), {});
示例:
document.getElementById('foobar').addEventListener('submit', (e) => {
e.preventDefault();
const formData = new FormData(e.target);
const data = Array.from(formData.entries()).reduce((memo, [key, value]) => ({
...memo,
[key]: value,
}), {});
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>
如果您有多个具有相同名称的条目,例如,如果您使用 <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 支持,因为它不支持 FormData
上的 ForEach
或 entries
)
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 );
}
你可以试试这个
formDataToJSON($('#form_example'));
# Create a function to convert the serialize and convert the form data
# to JSON
# @param : $('#form_example');
# @return a JSON Stringify
function formDataToJSON(form) {
let obj = {};
let formData = form.serialize();
let formArray = formData.split("&");
for (inputData of formArray){
let dataTmp = inputData.split('=');
obj[dataTmp[0]] = dataTmp[1];
}
return JSON.stringify(obj);
}
这个 post 已经一岁了...但是,我真的非常喜欢 ES6 @dzuc 的回答。然而,由于无法处理多个选择或复选框,它是不完整的。这已经指出并提供了代码解决方案。我发现它们很重而且没有优化。所以我基于@dzuc写了两个版本来处理这些情况:
- 对于 ASP 样式表单,其中多个项目名称可以简单重复。
let r=Array.from(fd).reduce(
(o , [k,v]) => (
(!o[k])
? {...o , [k] : v}
: {...o , [k] : [...o[k] , v]}
)
,{}
);
let obj=JSON.stringify(r);
一行Hotshot版本:
Array.from(fd).reduce((o,[k,v])=>((!o[k])?{...o,[k]:v}:{...o,[k]:[...o[k],v]}),{});
- 对于 PHP 样式表单,其中多个项目名称必须具有
[]
后缀。
let r=Array.from(fd).reduce(
(o , [k,v]) => (
(k.split('[').length>1)
? (k=k.split('[')[0]
, (!o[k])
? {...o , [k] : [v]}
: {...o , [k] : [...o[k] , v ]}
)
: {...o , [k] : v}
)
,{}
);
let obj=JSON.stringify(r);
一行Hotshot版本:
Array.from(fd).reduce((o,[k,v])=>((k.split('[').length>1)?(k=k.split('[')[0],(!o[k])?{...o,[k]:[v]}:{...o,[k]:[...o[k],v]}):{...o,[k]:v}),{});
- 支持多级数组的 PHP 形式的扩展。
自从上次写了前面的第二种情况,在工作中遇到了PHP表单多级checkbox的情况。我写了一个新案例来支持以前的案例和这个案例。我创建了一个片段来更好地展示这个案例,结果显示在这个演示的控制台上,根据你的需要修改它。试图在不影响性能的情况下尽我所能优化它,但是,它损害了一些人类的可读性。它利用了数组是对象并且指向数组的变量被保留为引用。没有这个能人,请客。
let nosubmit = (e) => {
e.preventDefault();
const f = Array.from(new FormData(e.target));
const obj = f.reduce((o, [k, v]) => {
let a = v,
b, i,
m = k.split('['),
n = m[0],
l = m.length;
if (l > 1) {
a = b = o[n] || [];
for (i = 1; i < l; i++) {
m[i] = (m[i].split(']')[0] || b.length) * 1;
b = b[m[i]] = ((i + 1) == l) ? v : b[m[i]] || [];
}
}
return { ...o, [n]: a };
}, {});
console.log(obj);
}
document.querySelector('#theform').addEventListener('submit', nosubmit, {capture: true});
<h1>Multilevel Form</h1>
<form action="#" method="POST" enctype="multipart/form-data" id="theform">
<input type="hidden" name="_id" value="93242" />
<input type="hidden" name="_fid" value="45c0ec96929bc0d39a904ab5c7af70ef" />
<label>Select:
<select name="uselect">
<option value="A">A</option>
<option value="B">B</option>
<option value="C">C</option>
</select>
</label>
<br /><br />
<label>Checkboxes one level:<br/>
<input name="c1[]" type="checkbox" checked value="1"/>v1
<input name="c1[]" type="checkbox" checked value="2"/>v2
<input name="c1[]" type="checkbox" checked value="3"/>v3
</label>
<br /><br />
<label>Checkboxes two levels:<br/>
<input name="c2[0][]" type="checkbox" checked value="4"/>0 v4
<input name="c2[0][]" type="checkbox" checked value="5"/>0 v5
<input name="c2[0][]" type="checkbox" checked value="6"/>0 v6
<br/>
<input name="c2[1][]" type="checkbox" checked value="7"/>1 v7
<input name="c2[1][]" type="checkbox" checked value="8"/>1 v8
<input name="c2[1][]" type="checkbox" checked value="9"/>1 v9
</label>
<br /><br />
<label>Radios:
<input type="radio" name="uradio" value="yes">YES
<input type="radio" name="uradio" checked value="no">NO
</label>
<br /><br />
<input type="submit" value="Submit" />
</form>
尽管@dzuc 的答案已经非常好,但您可以使用数组解构(在现代浏览器或 Babel 中可用)使其更加优雅:
// original version from @dzuc
const data = Array.from(formData.entries())
.reduce((memo, pair) => ({
...memo,
[pair[0]: pair[1],
}), {})
// with array destructuring
const data = Array.from(formData.entries())
.reduce((memo,[key, value]) => ({
...memo,
[key]: value,
}), {})
如果以下项目满足您的需求,那么您很幸运:
- 您想将像
[['key','value1'], ['key2','value2']
这样的数组(就像 FormData 给你的那样)转换成像{key1: 'value1', key2: 'value2'}
这样的键->值对象,然后将它转换成 JSON字符串. - 您的目标是 browsers/devices 使用最新的 ES6 解释器或使用 babel 之类的工具进行编译。
- 您想要完成此任务的最简单方法。
这是您需要的代码:
const data = new FormData(document.querySelector('form'));
const json = JSON.stringify(Array.from(data).reduce((o,[k,v])=>(o[k]=v,o),{}));
希望这对某人有所帮助。
辱骂单行!
Array.from(fd).reduce((obj, [k, v]) => ({...obj, [k]: v}), {});
今天我了解到 firefox 支持对象传播和数组解构!
为我工作
var myForm = document.getElementById("form");
var formData = new FormData(myForm),
obj = {};
for (var entry of formData.entries()){
obj[entry[0]] = entry[1];
}
console.log(obj);
2019年,这种任务变得超级简单。
JSON.stringify(Object.fromEntries(formData));
Object.fromEntries
:支持 Chrome 73+、Firefox 63+、Safari 12.1
如评论中所述,请注意:FormData
可以包含具有相同键的多个值(例如具有相同名称的复选框)。 Object.fromEntries()
丢弃重复项,只保留最后一个。
在我的例子中,表单数据是数据,fire base 需要一个对象,但数据包含对象以及所有其他东西,所以我试过 data.value 它有效!!!
我来晚了。但是,我做了一个简单的方法来检查输入类型="checkbox"
var formData = new FormData($form.get(0));
var objectData = {};
formData.forEach(function (value, key) {
var updatedValue = value;
if ($('input[name="' + key + '"]').attr("type") === "checkbox" && $('input[name="' + key + '"]').is(":checked")) {
updatedValue = true; // we don't set false due to it is by default on HTML
}
objectData[key] = updatedValue;
});
var jsonData = JSON.stringify(objectData);
我希望这对其他人有帮助。
如果您需要支持序列化嵌套字段,类似于PHP处理表单字段的方式,您可以使用以下函数
function update(data, keys, value) {
if (keys.length === 0) {
// Leaf node
return value;
}
let key = keys.shift();
if (!key) {
data = data || [];
if (Array.isArray(data)) {
key = data.length;
}
}
// Try converting key to a numeric value
let index = +key;
if (!isNaN(index)) {
// We have a numeric index, make data a numeric array
// This will not work if this is a associative array
// with numeric keys
data = data || [];
key = index;
}
// If none of the above matched, we have an associative array
data = data || {};
let val = update(data[key], keys, value);
data[key] = val;
return data;
}
function serializeForm(form) {
return Array.from((new FormData(form)).entries())
.reduce((data, [field, value]) => {
let [_, prefix, keys] = field.match(/^([^\[]+)((?:\[[^\]]*\])*)/);
if (keys) {
keys = Array.from(keys.matchAll(/\[([^\]]*)\]/g), m => m[1]);
value = update(data[prefix], keys, value);
}
data[prefix] = value;
return data;
}, {});
}
document.getElementById('output').textContent = JSON.stringify(serializeForm(document.getElementById('form')), null, 2);
<form id="form">
<input name="field1" value="Field 1">
<input name="field2[]" value="Field 21">
<input name="field2[]" value="Field 22">
<input name="field3[a]" value="Field 3a">
<input name="field3[b]" value="Field 3b">
<input name="field3[c]" value="Field 3c">
<input name="field4[x][a]" value="Field xa">
<input name="field4[x][b]" value="Field xb">
<input name="field4[x][c]" value="Field xc">
<input name="field4[y][a]" value="Field ya">
<input name="field5[z][0]" value="Field z0">
<input name="field5[z][]" value="Field z1">
<input name="field6.z" value="Field 6Z0">
<input name="field6.z" value="Field 6Z1">
</form>
<h2>Output</h2>
<pre id="output">
</pre>
到目前为止,我还没有看到有人提到 FormData.getAll 方法。
除了从 FormData 对象中返回与给定键关联的所有值外,使用此处其他人指定的 Object.fromEntries 方法变得非常简单。
var formData = new FormData(document.forms[0])
var obj = Object.fromEntries(
Array.from(formData.keys()).map(key => [
key, formData.getAll(key).length > 1 ?
formData.getAll(key) : formData.get(key)
])
)
实际片段
var formData = new FormData(document.forms[0])
var obj = Object.fromEntries(Array.from(formData.keys()).map(key => [key, formData.getAll(key).length > 1 ? formData.getAll(key) : formData.get(key)]))
document.write(`<pre>${JSON.stringify(obj)}</pre>`)
<form action="#">
<input name="name" value="Robinson" />
<input name="items" value="Vin" />
<input name="items" value="Fromage" />
<select name="animals" multiple id="animals">
<option value="tiger" selected>Tigre</option>
<option value="turtle" selected>Tortue</option>
<option value="monkey">Singe</option>
</select>
</form>
我认为这是从 formData
FormData 对象获得所需结果的最简单方法:
const jsonData = {};
for(const [key, value] of formData) {
jsonData[key] = value;
}
这对我有用。 Click here查看详情代码
let formToJson = function(){
let form = new FormData($("form#formData")[0]);
//console.log(form);
let jsonData = Object.fromEntries(form.entries());
//console.log(jsonData);
$("#jsonData").html(JSON.stringify(jsonData));
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<div class="">
<form action="#" method="post" id="formData">
<input type="text" name="fName" id="fName" value="Mad"><br>
<input type="text" name="lName" id="lName" value="Coder"><br>
<input type="button" onclick="formToJson()" value="Boom Yeah">
</form>
</div>
<div id="jsonData">
</div>
</body>
</html>
如果你想要 json 字符串:
var jsonStr = JSON.stringify($('#formId').serializeObject());
如果你想要一个 json 对象
var jsonObj = JSON.parse(JSON.stringify($('#formId').serializeObject()));
toJSON
If the value has a
toJSON()
method, it's responsible to define what data will be serialized.
这是一个小窍门。
var fd = new FormData(document.forms[0]);
fd.toJSON = function() {
const o = {};
this.forEach((v, k) => {
v = this.getAll(k);
o[k] = v.length == 1 ? v[0] : (v.length >= 1 ? v : null);
});
return o;
};
document.write(`<pre>${JSON.stringify(fd)}</pre>`)
<form action="#">
<input name="name" value="Robinson" />
<input name="items" value="Vin" />
<input name="items" value="Fromage" />
<select name="animals" multiple id="animals">
<option value="tiger" selected>Tigre</option>
<option value="turtle" selected>Tortue</option>
<option value="monkey">Singe</option>
</select>
</form>
这解决了我的问题,这是一个对象
const formDataObject = (formData) => {
for (const key in formData) {
if (formData[key].startsWith('{') || formData[key].startsWith('[')) {
try {
formData[key] = JSON.parse(formData[key]);
console.log("key is :", key, "form data is :", formData[key]);
} catch (error) {
console.log("error :", key);
}
}
}
console.log("object", formData)
}
另一种适用于 select 多个或具有相同名称属性的输入的方法:
function form_to_json() {
const form_data = new FormData(document.querySelector('form'))
const uniqueKeys = [...new Set(form_data.keys())]
const obj = {}
uniqueKeys.forEach((value, key) => {
obj[value] = (form_data.getAll(value).length > 1) ? form_data.getAll(value) : form_data.get(value)
})
const json = JSON.stringify(obj)
alert(json)
}
<form>
<input type="text" name="name" value="Cesar"></br>
<select name="cars" id="cars" multiple>
<option value="volvo" selected>Volvo</option>
<option value="saab" selected>Saab</option>
</select>
<input type="button" onclick="form_to_json()" value="Ok">
</form>
我知道已经晚了,但这是解决方案;
new URLSearchParams(new FormData(formElement)).toString()
现在,可以将其作为正文发送。遗憾的是,它不是 JSON。
这是一个将 formData 对象转换为 JSON-string 的函数。
- 适用于多个条目和嵌套数组。
- 适用于编号和命名输入名称数组。
例如,您可以有以下表单字段:
<select name="select[]" multiple></select>
<input name="check[a][0][]" type="checkbox" value="test"/>
用法:
let json = form2json(formData);
函数:
function form2json(data) {
let method = function (object,pair) {
let keys = pair[0].replace(/\]/g,'').split('[');
let key = keys[0];
let value = pair[1];
if (keys.length > 1) {
let i,x,segment;
let last = value;
let type = isNaN(keys[1]) ? {} : [];
value = segment = object[key] || type;
for (i = 1; i < keys.length; i++) {
x = keys[i];
if (i == keys.length-1) {
if (Array.isArray(segment)) {
segment.push(last);
} else {
segment[x] = last;
}
} else if (segment[x] == undefined) {
segment[x] = isNaN(keys[i+1]) ? {} : [];
}
segment = segment[x];
}
}
object[key] = value;
return object;
}
let object = Array.from(data).reduce(method,{});
return JSON.stringify(object);
}
多年后在 vanillaJs (es6) 中
let body = new FormData()
body.set('key1', 'value AA')
body.set('key2', 'value BB')
let data = [...body.keys()].reduce( (acc, key, idx) => {
acc[key] = body.get(key)
return acc
} , {} )
console.log(JSON.stringify(data)) // {key1: 'value AA', key2: 'value BB'}
这是一种包含处理多个值的简单方法的方法。如果键以 []
结尾,它会将值组合到一个数组中(就像在旧的 php 约定中一样),并从键中删除 []
:
function formDataToJson(f) {
return Object.fromEntries(Array.from(f.keys(), k =>
k.endsWith('[]') ? [k.slice(0, -2), f.getAll(k)] : [k, f.get(k)]));
}
例如,如果您有:
const f = new FormData();
f.append("a", "1");
f.append("a", "2");
f.append("b[]", "3");
f.append("b[]", "4");
formDataToJson(f) // --> produces {a: "1", b: ["3","4"]}