我如何将条目从HTML5 FormData对象转换为JSON?

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


当前回答

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

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

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

正如评论中提到的,请注意:FormData可以包含多个具有相同键的值(例如具有相同名称的复选框)。fromentries()丢弃重复项,只保留最后一个。

其他回答

下面是一个将formData对象转换为json字符串的函数。

适用于多个条目和嵌套数组。 适用于编号和命名的输入名称数组。

例如,你可以有以下表单字段:

<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);
        
    }

对于我的目的,包括多选,如复选框,这是很好的:

JSON.stringify(Array.from((new FormData(document.querySelector('form'))).entries()).reduce((map = {}, [key, value]) => {
    return {
        ...map,
        [key]: map[key] ? [...map[key], value] : value,
    };
}, {}));

简单易用的功能

我已经为此创建了一个函数

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变量,我在每个迭代中都使用了从formData Object到JSON key的键。

你在GitHub上找到我的JS库中的此代码,如果需要改进,请建议我,我已经在这里放置了代码https://github.com/alijamal14/Utilities/blob/master/Utilities.js

另一种适用于选择多个或具有相同name属性的输入的方法:

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>

这篇文章已经有一年了……但是,我真的非常非常喜欢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);

一行高手版:

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);

一行高手版:

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表单扩展。

Since last time I wrote the previous second case, at work it came a case that the PHP form has checkboxes on multi-levels. I wrote a new case to support previous case and this one. I created a snippet to better showcase this case, the result show on the console for this demo, modify this to your need. Tried to optimize it the best I could without compromising performance, however, it compromise some human readability. It takes advantage that arrays are objects and variables pointing to arrays are kept as reference. No hotshot for this one, be my guest.

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>