使用jQuery将表单数据转换为JavaScript对象

Convert form data to JavaScript object with jQuery

提问人: 提问时间:7/26/2009 最后编辑:8 revs, 6 users 42%Yisroel 更新时间:7/4/2023 访问量:1091142

问:

如何将表单的所有元素转换为 JavaScript 对象?

我希望有某种方法可以从我的表单自动构建 JavaScript 对象,而不必遍历每个元素。我不想要 返回的字符串,也不想要 返回的映射$('#formid').serialize();$('#formid').serializeArray();

JavaScript jQuery JSON 序列化

评论

19赞 Yisroel 7/26/2009
因为第一个返回一个字符串,就像你使用 GET 方法提交表单时得到的字符串一样,第二个给你一个对象数组,每个对象都有一个名称值对。我希望如果我有一个名为“email”的字段,我会得到一个对象,该对象将允许我使用 obj.email 检索该值。使用 serializeArray(),我必须执行类似 obj[indexOfElement].value 之类的操作

答:

24赞 tvanfosson #1

如果不检查每个元素,真的没有办法做到这一点。您真正想知道的是“其他人是否已经编写了将表单转换为JSON对象的方法?像下面这样的东西应该可以工作 - 请注意,它只会给你通过POST返回的表单元素(必须有一个名称)。这未经测试

function formToJSON( selector )
{
     var form = {};
     $(selector).find(':input[name]:enabled').each( function() {
         var self = $(this);
         var name = self.attr('name');
         if (form[name]) {
            form[name] = form[name] + ',' + self.val();
         }
         else {
            form[name] = self.val();
         }
     });

     return form;
}

评论

0赞 gre_gor 8/13/2022
此函数返回对象,而不是 JSON 字符串。
0赞 Jason Berry #2

由于 XSS 攻击和可能还有很多其他问题,我不会在实时站点上使用它,但这里有一个您可以执行的操作的简单示例:

$("#myform").submit(function(){
    var arr = $(this).serializeArray();
    var json = "";
    jQuery.each(arr, function(){
        jQuery.each(this, function(i, val){
            if (i=="name") {
                json += '"' + val + '":';
            } else if (i=="value") {
                json += '"' + val.replace(/"/g, '\\"') + '",';
            }
        });
    });
    json = "{" + json.substring(0, json.length - 1) + "}";
    // do something with json
    return false;
});

评论

0赞 davidtgq 5/27/2016
难道你不能通过先将它们转换为 JS 对象而不是直接转换为字符串来绕过 XSS 攻击吗?
1734赞 12 revs, 11 users 49%Tobias Cohen #3

serializeArray 已经做到了这一点。您只需要将数据调整为所需的格式:

function objectifyForm(formArray) {
    //serialize data function
    var returnArray = {};
    for (var i = 0; i < formArray.length; i++){
        returnArray[formArray[i]['name']] = formArray[i]['value'];
    }
    return returnArray;
}

注意与实际输入同名的隐藏字段,因为它们将被覆盖。

评论

71赞 Tobias Cohen 7/28/2009
你的意思是“为什么首先使用serializeArray来获取数据?因为serializeArray已经编写好了,所以在多个浏览器中进行了单元测试,理论上可以在更高版本的jQuery中得到改进。你编写的代码越少,必须直接访问不一致的东西,比如 DOM 元素,你的代码就越稳定。
61赞 Samuel Meacham 7/19/2010
请注意,serializeArray() 将不包含禁用的元素。我经常禁用与页面上其他元素同步的输入元素,但我仍然希望它们包含在我的序列化对象中。你最好使用一些东西,比如如果你需要包含禁用的元素。$.map( $("#container :input"), function(n, i) { /* n.name and $(n).val() */ } );
1赞 PaPaFox552 3/31/2023
多个名称仅返回最后一个。
0赞 wordpress user 9/24/2023
不适用于多维数组
3赞 kflorence #4

我更喜欢这种方法,因为:您不必遍历 2 个集合,如果需要,您可以获取“名称”和“值”以外的内容,并且可以在将值存储在对象中之前对其进行清理(例如,如果您有不希望存储的默认值)。

$.formObject = function($o) {
    var o = {},
        real_value = function($field) {
            var val = $field.val() || "";

            // additional cleaning here, if needed

            return val;
        };

    if (typeof o != "object") {
        $o = $(o);
    }

    $(":input[name]", $o).each(function(i, field) {
        var $field = $(field),
            name = $field.attr("name"),
            value = real_value($field);

        if (o[name]) {
            if (!$.isArray(o[name])) {
                o[name] = [o[name]];
            }

            o[name].push(value);
        }

        else {
            o[name] = value;
        }
    });

    return o;
}

像这样使用:

var obj = $.formObject($("#someForm"));

仅在 Firefox 中测试。

20赞 2 revsSamuel Meacham #5

好的,我知道这已经有了一个高度赞成的答案,但最近又问了另一个类似的问题,我也被引导到这个问题上。我也想提供我的解决方案,因为它比公认的解决方案更具优势:您可以包含禁用的表单元素(这有时很重要,具体取决于您的 UI 功能)

这是我对另一个 SO 问题的回答:

最初,我们使用的是jQuery的方法,但这不包括禁用的表单元素。我们通常会禁用“同步”到页面上其他源的表单元素,但我们仍然需要将数据包含在序列化对象中。所以出来了。我们使用选择器获取给定容器中的所有输入元素(启用和禁用),然后创建我们的对象。serializeArray()serializeArray():input$.map()

var inputs = $("#container :input");
var obj = $.map(inputs, function(n, i)
{
    var o = {};
    o[n.name] = $(n).val();
    return o;
});
console.log(obj);

请注意,要做到这一点,您的每个输入都需要一个属性,该属性将是结果对象的属性名称。name

这实际上与我们使用的略有修改。我们需要创建一个结构为 .NET IDictionary 的对象,因此我们使用了这个: (我在这里提供它,以防万一有用)

var obj = $.map(inputs, function(n, i)
{
    return { Key: n.name, Value: $(n).val() };
});
console.log(obj);

我喜欢这两种解决方案,因为它们是函数的简单用法,并且您可以完全控制选择器(因此,您最终会在生成的对象中包含哪些元素)。此外,不需要额外的插件。普通的旧jQuery。$.map()

评论

6赞 joshperry 10/2/2010
我在一个项目中尝试过这个,使用这样的方法创建一个具有单个属性的对象数组,它不会将所有属性折叠成一个对象。map
6赞 user1134789 #6

我发现 Tobias Cohen 的代码有问题(我没有足够的观点直接评论它),否则对我有用。如果有两个同名的选择选项,并且都具有 value=“”,则原始代码将生成 “name”:“” 而不是 “name”:[“”,“”]

我认为这可以通过添加“ ||o[this.name] == ''“ 添加到第一个 if 条件:

$.fn.serializeObject = function()
{
    var o = {};
    var a = this.serializeArray();
    $.each(a, function() {
        if (o[this.name] || o[this.name] == '') {
            if (!o[this.name].push) {
                o[this.name] = [o[this.name]];
            }
            o[this.name].push(this.value || '');
        } else {
            o[this.name] = this.value || '';
        }
    });
    return o;
};
107赞 Daniel X Moore #7

Tobias Cohen 解决方案的固定版本。这个可以正确处理像 和 这样的虚假值。0''

jQuery.fn.serializeObject = function() {
  var arrayData, objectData;
  arrayData = this.serializeArray();
  objectData = {};

  $.each(arrayData, function() {
    var value;

    if (this.value != null) {
      value = this.value;
    } else {
      value = '';
    }

    if (objectData[this.name] != null) {
      if (!objectData[this.name].push) {
        objectData[this.name] = [objectData[this.name]];
      }

      objectData[this.name].push(value);
    } else {
      objectData[this.name] = value;
    }
  });

  return objectData;
};

以及 CoffeeScript 版本,方便您编码:

jQuery.fn.serializeObject = ->
  arrayData = @serializeArray()
  objectData = {}

  $.each arrayData, ->
    if @value?
      value = @value
    else
      value = ''

    if objectData[@name]?
      unless objectData[@name].push
        objectData[@name] = [objectData[@name]]

      objectData[@name].push value
    else
      objectData[@name] = value

  return objectData
29赞 Jeffrey Van Alstine #8

所有这些答案在我看来都太过分了。为了简单起见,有一些话要说。只要您的所有表单输入都设置了 name 属性,这应该可以正常工作,只是 jim dandy。

$('form.myform').submit(function () {
  var $this = $(this)
    , viewArr = $this.serializeArray()
    , view = {};

  for (var i in viewArr) {
    view[viewArr[i].name] = viewArr[i].value;
  }

  //Do stuff with view object here (e.g. JSON.stringify?)
});
2赞 2 revsFrank Nocke #9

我喜欢塞缪尔版本,但我相信它有一个小错误。通常,JSON 作为

{“coreSKU”:“PCGUYJS”,“name_de”:“随便”,...

不作为

[{“coreSKU”:“PCGUYJS”},{“name_de”:“随便”},...

因此,IMO函数应为:

App.toJson = function( selector ) {
    var o = {};
    $.map( $( selector ), function( n,i )
    {
        o[n.name] = $(n).val();
    });     
    return o;
}

并将其包装在数据数组中(通常也是如此),最后将其作为字符串发送 App.stringify( {data:App.toJson( '#cropform :input' )} )

对于精益版本,请查看问题 3593046,对于所有可能性涵盖的版本,请查看 json2.js。这应该涵盖所有:)

评论

0赞 Adarsha 4/28/2018
谢谢。。这使得(正如你提到的)微小但非常重要的区别。
2赞 2 revs, 2 users 95%Sammaye #10

我发现所选解决方案有问题。

当使用具有基于数组的名称的表单时,jQuery serializeArray() 函数实际上会死。

我有一个PHP框架,它使用基于数组的字段名称,允许在多个视图中多次将同一表单放到同一页面上。这样可以方便地将添加、编辑和删除放在同一页面上,而不会发生冲突表单模型。

由于我想在不删除这个绝对基本功能的情况下将表单化,因此我决定编写自己的 seralizeArray():

        var $vals = {};

        $("#video_edit_form input").each(function(i){
            var name = $(this).attr("name").replace(/editSingleForm\[/i, '');

            name = name.replace(/\]/i, '');

            switch($(this).attr("type")){
                case "text":
                    $vals[name] = $(this).val();
                    break;
                case "checkbox":
                    if($(this).attr("checked")){
                        $vals[name] = $(this).val();
                    }
                    break;
                case "radio":
                    if($(this).attr("checked")){
                        $vals[name] = $(this).val();
                    }
                    break;
                default:
                    break;
            }
        });

请注意:这也适用于表单submit(),因此,如果代码的其余部分发生错误,如果您放置一个链接按钮,上面写着“保存更改”,则表单将不会提交。

另请注意,此函数绝不应用于验证表单,仅用于收集要发送到服务器端进行验证的数据。使用这种弱代码和大量分配的代码会导致 XSS 等。

-1赞 Anoop #11

serialize 函数将 JSON 对象作为参数并返回 serialize String。

function serialize(object) {
            var _SPECIAL_CHARS = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, _CHARS = {
                '\b' : '\\b',
                '\t' : '\\t',
                '\n' : '\\n',
                '\f' : '\\f',
                '\r' : '\\r',
                '"' : '\\"',
                '\\' : '\\\\'
            }, EMPTY = '', OPEN_O = '{', CLOSE_O = '}', OPEN_A = '[', CLOSE_A = ']', COMMA = ',', COMMA_CR = ",\n", CR = "\n", COLON = ':', space = "", COLON_SP = ': ', stack = [], QUOTE = '"';
            function _char(c) {
                if (!_CHARS[c]) {
                    _CHARS[c] = '\\u' + ('0000' + (+(c.charCodeAt(0))).toString(16))
                        .slice(-4);
                }
                return _CHARS[c];
            }
            function _string(s) {
                return QUOTE + s.replace(_SPECIAL_CHARS, _char) + QUOTE;
                // return str.replace('\"','').replace('\"','');
            }

            function serialize(h, key) {
                var value = h[key], a = [], colon = ":", arr, i, keys, t, k, v;
                arr = value instanceof Array;
                stack.push(value);
                keys = value;
                i = 0;
                t = typeof value;
                switch (t) {
                    case "object" :
                        if(value==null){
                            return null;
                        }
                        break;
                    case "string" :
                        return _string(value);
                    case "number" :
                        return isFinite(value) ? value + EMPTY : NULL;
                    case "boolean" :
                        return value + EMPTY;
                    case "null" :
                        return null;
                    default :
                        return undefined;
                }
                arr = value.length === undefined ? false : true;

                if (arr) { // Array
                    for (i = value.length - 1; i >= 0; --i) {
                        a[i] = serialize(value, i) || NULL;
                    }
                }
                else { // Object
                    i = 0;
                    for (k in keys) {
                        if (keys.hasOwnProperty(k)) {
                            v = serialize(value, k);
                            if (v) {
                                a[i++] = _string(k) + colon + v;
                            }
                        }
                    }
                }

                stack.pop();
                if (space && a.length) {

                    return arr
                        ? "[" + _indent(a.join(COMMA_CR), space) + "\n]"
                        : "{\n" + _indent(a.join(COMMA_CR), space) + "\n}";
                }
                else {
                    return arr ? "[" + a.join(COMMA) + "]" : "{" + a.join(COMMA)
                        + "}";
                }
            }
            return serialize({
                "" : object
            }, "");
        }
471赞 9 revs, 3 users 89%maček #12

像老板一样将表单转换为JSON


当前源位于 GitHubBower 上。

$ bower 安装 jquery-serialize-object


以下代码现已弃用

以下代码可以处理各种输入名称;并按照您的期望处理它们。

例如:

<!-- All of these will work! -->
<input name="honey[badger]" value="a">
<input name="wombat[]" value="b">
<input name="hello[panda][]" value="c">
<input name="animals[0][name]" value="d">
<input name="animals[0][breed]" value="e">
<input name="crazy[1][][wonky]" value="f">
<input name="dream[as][vividly][as][you][can]" value="g">
// Output
{
  "honey":{
    "badger":"a"
  },
  "wombat":["b"],
  "hello":{
    "panda":["c"]
  },
  "animals":[
    {
      "name":"d",
      "breed":"e"
    }
  ],
  "crazy":[
    null,
    [
      {"wonky":"f"}
    ]
  ],
  "dream":{
    "as":{
      "vividly":{
        "as":{
          "you":{
            "can":"g"
          }
        }
      }
    }
  }
}

用法

$('#my-form').serializeObject();

巫术 (JavaScript)

(function($){
    $.fn.serializeObject = function(){

        var self = this,
            json = {},
            push_counters = {},
            patterns = {
                "validate": /^[a-zA-Z][a-zA-Z0-9_]*(?:\[(?:\d*|[a-zA-Z0-9_]+)\])*$/,
                "key":      /[a-zA-Z0-9_]+|(?=\[\])/g,
                "push":     /^$/,
                "fixed":    /^\d+$/,
                "named":    /^[a-zA-Z0-9_]+$/
            };


        this.build = function(base, key, value){
            base[key] = value;
            return base;
        };

        this.push_counter = function(key){
            if(push_counters[key] === undefined){
                push_counters[key] = 0;
            }
            return push_counters[key]++;
        };

        $.each($(this).serializeArray(), function(){

            // Skip invalid keys
            if(!patterns.validate.test(this.name)){
                return;
            }

            var k,
                keys = this.name.match(patterns.key),
                merge = this.value,
                reverse_key = this.name;

            while((k = keys.pop()) !== undefined){

                // Adjust reverse_key
                reverse_key = reverse_key.replace(new RegExp("\\[" + k + "\\]$"), '');

                // Push
                if(k.match(patterns.push)){
                    merge = self.build([], self.push_counter(reverse_key), merge);
                }

                // Fixed
                else if(k.match(patterns.fixed)){
                    merge = self.build([], k, merge);
                }

                // Named
                else if(k.match(patterns.named)){
                    merge = self.build({}, k, merge);
                }
            }

            json = $.extend(true, json, merge);
        });

        return json;
    };
})(jQuery);

评论

18赞 frontendbeauty 12/29/2011
所以,这很有效。但它的命名是错误的:顾名思义,它不返回 JSON。相反,它返回一个对象文本。此外,检查 hasOwnProperty 也很重要,否则您的数组会附加到其原型的任何内容,例如:{numbers: [“1”, “3”, indexOf: function(){...}]}
2赞 eithed #13

将任何东西变成对象(未经单元测试)

<script type="text/javascript">
string = {};

string.repeat = function(string, count)
{
    return new Array(count+1).join(string);
}

string.count = function(string)
{
    var count = 0;

    for (var i=1; i<arguments.length; i++)
    {
        var results = string.match(new RegExp(arguments[i], 'g'));
        count += results ? results.length : 0;
    }

    return count;
}

array = {};

array.merge = function(arr1, arr2)
{
    for (var i in arr2)
    {
        if (arr1[i] && typeof arr1[i] == 'object' && typeof arr2[i] == 'object')
            arr1[i] = array.merge(arr1[i], arr2[i]);
        else
            arr1[i] = arr2[i]
    }

    return arr1;
}

array.print = function(obj)
{
    var arr = [];
    $.each(obj, function(key, val) {
        var next = key + ": ";
        next += $.isPlainObject(val) ? array.print(val) : val;
        arr.push( next );
      });

    return "{ " +  arr.join(", ") + " }";
}

node = {};

node.objectify = function(node, params)
{
    if (!params)
        params = {};

    if (!params.selector)
        params.selector = "*";

    if (!params.key)
        params.key = "name";

    if (!params.value)
        params.value = "value";

    var o = {};
    var indexes = {};

    $(node).find(params.selector+"["+params.key+"]").each(function()
    {
        var name = $(this).attr(params.key),
            value = $(this).attr(params.value);

        var obj = $.parseJSON("{"+name.replace(/([^\[]*)/, function()
        {
            return '"'+arguments[1]+'"';
        }).replace(/\[(.*?)\]/gi, function()
        {
            if (arguments[1].length == 0)
            {
                var index = arguments[3].substring(0, arguments[2]);
                indexes[index] = indexes[index] !== undefined ? indexes[index]+1 : 0;

                return ':{"'+indexes[index]+'"';
            }
            else
                return ':{"'+escape(arguments[1])+'"';
        })+':"'+value.replace(/[\\"]/gi, function()
        {
            return "\\"+arguments[0]; 
        })+'"'+string.repeat('}', string.count(name, ']'))+"}");

        o = array.merge(o, obj);
    });

    return o;
}
</script>

测试输出:

$(document).ready(function()
{
    console.log(array.print(node.objectify($("form"), {})));
    console.log(array.print(node.objectify($("form"), {selector: "select"})));
});

<form>
    <input name='input[a]' type='text' value='text'/>
    <select name='input[b]'>
        <option>select</option>
    </select>

    <input name='otherinput[c][a]' value='a'/>
    <input name='otherinput[c][]' value='b'/>
    <input name='otherinput[d][b]' value='c'/>
    <input name='otherinput[c][]' value='d'/>

    <input type='hidden' name='anotherinput' value='hidden'/>
    <input type='hidden' name='anotherinput' value='1'/>

    <input type='submit' value='submit'/>
</form>

将产生:

{ input: { a: text, b: select }, otherinput: { c: { a: a, 0: b, 1: d }, d: { b: c } }, anotherinput: 1 }
{ input: { b: select } }
1赞 3 revs, 2 users 75%Kevin Jhangiani #14

上面的 Tobias 解决方案是正确的,但是,正如评论者 @macek 指出的那样,它不处理 foo[bar] 类型的输入并将它们拆分为子对象。

这是一个仅限PHP的功能,但我仍然发现能够在JavaScript中生成相同的结构非常有用。

我只是修改了上面 Tobias 的代码,所以所有的功劳都归功于他。这也许可以变得更干净,但我只是在五分钟内把它搅动起来,并认为它可能有用。

它目前不处理多维数组或数字索引数组。也就是说,它仅适用于名称 foo[bar] 而不是 foo[]。

jQuery.fn.serializeObjectPHP = function()
{
    var o = {};
    var re = /^(.+)\[(.*)\]$/;
    var a = this.serializeArray();
    var n;
    jQuery.each(a, function() {
        var name = this.name;
        if ((n = re.exec(this.name)) && n[2]) {
            if (o[n[1]] === undefined) {
                o[n[1]] = {};
                o[n[1]][n[2]] = this.value || '';
            } else if (o[n[1]][n[2]] === undefined) {
                o[n[1]][n[2]] = this.value || '';
            } else {
                if(!o[n[1]][n[2]].push) {
                    o[n[1]][n[2]] = [ o[n[1]][n[2]] ];
                }
                o[n[1]][n[2]].push(this.value || '');
            }
        } else {
            if (n && !n[2]) {
                name = n[1];
            }
            if (o[name] !== undefined) {
                if (!o[name].push) {
                    o[name] = [o[name]];
                }
                o[name].push(this.value || '');
            } else {
                o[name] = this.value || '';
            }
        }
    });
    return o;
};

评论

0赞 maček 5/22/2012
好像你没有读过我的整个评论。我设计了一个解决方案,可以处理 -type 输入以及 ;在此线程中查看我的答案。另请注意,“解析”并非 PHP 所独有。Rails 在很大程度上依赖于这个约定来将表单属性传递给对象。foo[bar]foo[bar][bof][a][b][c][etc]foo[bar]
17赞 Sergey Varlamov #15

此函数应处理多维数组以及具有相同名称的多个元素。

到目前为止,我已经使用它几年了:

jQuery.fn.serializeJSON=function() {
  var json = {};
  jQuery.map(jQuery(this).serializeArray(), function(n, i) {
    var _ = n.name.indexOf('[');
    if (_ > -1) {
      var o = json;
      _name = n.name.replace(/\]/gi, '').split('[');
      for (var i=0, len=_name.length; i<len; i++) {
        if (i == len-1) {
          if (o[_name[i]]) {
            if (typeof o[_name[i]] == 'string') {
              o[_name[i]] = [o[_name[i]]];
            }
            o[_name[i]].push(n.value);
          }
          else o[_name[i]] = n.value || '';
        }
        else o = o[_name[i]] = o[_name[i]] || {};
      }
    }
    else {
      if (json[n.name] !== undefined) {
        if (!json[n.name].push) {
          json[n.name] = [json[n.name]];
        }
        json[n.name].push(n.value || '');
      }
      else json[n.name] = n.value || '';      
    }
  });
  return json;
};
0赞 2 revs, 2 users 74%Kipras #16

这是对 Tobias Cohen 函数的改进,该函数适用于多维数组:

http://jsfiddle.net/BNnwF/2/

然而,这不是一个jQuery插件,但如果你想以这种方式使用它,只需要几秒钟就可以把它变成一个插件:只需替换函数声明包装器:

function serializeFormObject(form)
{
    ...
}

跟:

$.fn.serializeFormObject = function()
{
    var form = this;
    ...
};

我想它类似于 macek 的解决方案,因为它做同样的事情,但我认为这更干净、更简单。我还将 macek 的测试用例输入包含在小提琴中,并添加了一些额外的输入。到目前为止,这对我来说效果很好。

function serializeFormObject(form)
{
    function trim(str)
    {
        return str.replace(/^\s+|\s+$/g,"");
    }

    var o = {};
    var a = $(form).serializeArray();
    $.each(a, function() {
        var nameParts = this.name.split('[');
        if (nameParts.length == 1) {
            // New value is not an array - so we simply add the new
            // value to the result object
            if (o[this.name] !== undefined) {
                if (!o[this.name].push) {
                    o[this.name] = [o[this.name]];
                }
                o[this.name].push(this.value || '');
            } else {
                o[this.name] = this.value || '';
            }
        }
        else {
            // New value is an array - we need to merge it into the
            // existing result object
            $.each(nameParts, function (index) {
                nameParts[index] = this.replace(/\]$/, '');
            });

            // This $.each merges the new value in, part by part
            var arrItem = this;
            var temp = o;
            $.each(nameParts, function (index) {
                var next;
                var nextNamePart;
                if (index >= nameParts.length - 1)
                    next = arrItem.value || '';
                else {
                    nextNamePart = nameParts[index + 1];
                    if (trim(this) != '' && temp[this] !== undefined)
                        next = temp[this];
                    else {
                        if (trim(nextNamePart) == '')
                            next = [];
                        else
                            next = {};
                    }
                }

                if (trim(this) == '') {
                    temp.push(next);
                } else
                    temp[this] = next;

                temp = next;
            });
        }
    });
    return o;
}
2赞 3 revs, 2 users 94%Onheiron #17

我最近遇到了同样的问题,并提出了这个 .toJSON jQuery 插件,它将表单转换为具有相同结构的 JSON 对象。这对于动态生成的表单也非常有用,在这些表单中,您希望让用户在特定位置添加更多字段。

关键是,你实际上可能想要构建一个表单,以便它本身有一个结构,所以假设你想制作一个表单,用户在其中插入他最喜欢的城市:你可以想象这个表单表示一个XML元素,其中包含用户喜欢的地方列表,因此是一个元素列表,每个元素都包含一个元素, 一个元素,然后是一个元素列表,用于表示您可以在此类位置执行的活动。因此,您的 XML 结构将如下所示:<places>...</places><place>...</place><name>...</name><type>...</type><activity>...</activity>

<places>

    <place>

        <name>Home</name>
        <type>dwelling</type>

        <activity>sleep</activity>
        <activity>eat</activity>
        <activity>watch TV</activity>

    </place>

    <place>...</place>

    <place>...</place>

</places>

如果有一个 JSON 对象来表示这个确切的结构,那将是多么酷,这样你就能够:

  • 将此对象存储在任何类似 CouchDB 的数据库中
  • 从 $_POST[] 服务器端读取它,并检索一个正确嵌套的数组,然后您可以对其进行语义操作
  • 使用一些服务器端脚本将其转换为格式正确的 XML 文件(即使您事先不知道其确切结构)
  • 只需以某种方式使用它,就像在任何类似 Node.js 的服务器脚本中一样

好了,现在我们需要考虑表单如何表示XML文件。

当然,标签是 ,但是我们有一个元素,它是一个容器,而不是数据元素本身,所以我们不能为它使用输入标签。<form>root<place>

这就是标签派上用场的地方!我们将使用标记来表示表单/XML 表示中的所有容器元素,从而得到如下结果:<fieldset><fieldset>

<form name="places">

    <fieldset name="place">

        <input type="text" name="name"/>
        <select name="type">
            <option value="dwelling">Dwelling</option>
            <option value="restoration">Restoration</option>
            <option value="sport">Sport</option>
            <option value="administrative">Administrative</option>
        </select>

        <input type="text" name="activity"/>
        <input type="text" name="activity"/>
        <input type="text" name="activity"/>

    </fieldset>

</form>

正如你在这个形式中看到的,我们打破了唯一名称的规则,但这没关系,因为它们将被转换为元素数组,因此它们将仅由数组中的索引引用。

在这一点上,你可以看到表单中没有类似的名字,一切都很漂亮、简单和语义化。name="array[]"

现在,我们希望将此表单转换为JSON对象,如下所示:

{'places':{

    'place':[

        {

            'name': 'Home',
            'type': 'dwelling',

            'activity':[

                 'sleep',
                 'eat',
                 'watch TV'

            ]

        },

        {...},

        {...}

    ]

}}

为此,我在这里开发了这个jQuery插件,有人在此代码审查线程中帮助优化了该插件,如下所示:

$.fn.toJSO = function () {
    var obj = {},
        $kids = $(this).children('[name]');
    if (!$kids.length) {
        return $(this).val();
    }
    $kids.each(function () {
        var $el = $(this),
            name = $el.attr('name');
        if ($el.siblings("[name=" + name + "]").length) {
            if (!/radio|checkbox/i.test($el.attr('type')) || $el.prop('checked')) {
                obj[name] = obj[name] || [];
                obj[name].push($el.toJSO());
            }
        } else {
            obj[name] = $el.toJSO();
        }
    });
    return obj;
};

我还写了这篇博文来解释这一点。

这会将表单中的所有内容转换为 JSON(甚至是单选和复选框),您剩下要做的就是调用

$.post('script.php',('form').toJSO(), ...);

我知道有很多方法可以将表单转换为JSON对象,并且在大多数情况下肯定并且工作得很好,并且主要用于使用,但我认为将表单编写为具有有意义的名称的XML结构并将其转换为格式良好的JSON对象的整个想法值得一试, 此外,如果您需要检索动态生成的表单数据,您可以放心地添加同名输入标签这一事实非常有用。.serialize().serializeArray()

我希望这对某人有所帮助!

评论

0赞 Carlo Moretti 9/2/2013
你想做什么?
0赞 2 revs, 2 users 70%pocesar #18

我的库 phery 中的代码有一个序列化例程,可以处理非常复杂的表单(如在演示 https://github.com/pocesar/phery/blob/master/demo.php#L1664 中),而且它不是一刀切的。它实际上检查每个字段的类型。例如,单选框与范围不同,与注册机不同,与选择多个不同。我的函数涵盖了所有内容,你可以看到 它在 https://github.com/pocesar/phery/blob/master/phery.js#L1851

serializeForm:function (opt) {
    opt = $.extend({}, opt);

    if (typeof opt['disabled'] === 'undefined' || opt['disabled'] === null) {
        opt['disabled'] = false;
    }
    if (typeof opt['all'] === 'undefined' || opt['all'] === null) {
        opt['all'] = false;
    }
    if (typeof opt['empty'] === 'undefined' || opt['empty'] === null) {
        opt['empty'] = true;
    }

    var
        $form = $(this),
        result = {},
        formValues =
            $form
                .find('input,textarea,select,keygen')
                .filter(function () {
                    var ret = true;
                    if (!opt['disabled']) {
                        ret = !this.disabled;
                    }
                    return ret && $.trim(this.name);
                })
                .map(function () {
                    var
                        $this = $(this),
                        radios,
                        options,
                        value = null;

                    if ($this.is('[type="radio"]') || $this.is('[type="checkbox"]')) {
                        if ($this.is('[type="radio"]')) {
                            radios = $form.find('[type="radio"][name="' + this.name + '"]');
                            if (radios.filter('[checked]').size()) {
                                value = radios.filter('[checked]').val();
                            }
                        } else if ($this.prop('checked')) {
                            value = $this.is('[value]') ? $this.val() : 1;
                        }
                    } else if ($this.is('select')) {
                        options = $this.find('option').filter(':selected');
                        if ($this.prop('multiple')) {
                            value = options.map(function () {
                                return this.value || this.innerHTML;
                            }).get();
                        } else {
                            value = options.val();
                        }
                    } else {
                        value = $this.val();
                    }

                    return {
                        'name':this.name || null,
                        'value':value
                    };
                }).get();

    if (formValues) {
        var
            i,
            value,
            name,
            $matches,
            len,
            offset,
            j,
            fields;

        for (i = 0; i < formValues.length; i++) {
            name = formValues[i].name;
            value = formValues[i].value;

            if (!opt['all']) {
                if (value === null) {
                    continue;
                }
            } else {
                if (value === null) {
                    value = '';
                }
            }

            if (value === '' && !opt['empty']) {
                continue;
            }

            if (!name) {
                continue;
            }

            $matches = name.split(/\[/);

            len = $matches.length;

            for (j = 1; j < len; j++) {
                $matches[j] = $matches[j].replace(/\]/g, '');
            }

            fields = [];

            for (j = 0; j < len; j++) {
                if ($matches[j] || j < len - 1) {
                    fields.push($matches[j].replace("'", ''));
                }
            }

            if ($matches[len - 1] === '') {
                offset = assign_object(result, fields, [], true, false, false);

                if (value.constructor === Array) {
                    offset[0][offset[1]].concat(value);
                } else {
                    offset[0][offset[1]].push(value);
                }
            } else {
                assign_object(result, fields, value);
            }
        }
    }

    return result;
}

它是我库的一部分,但它可以移植到你自己的项目中。它在应该有数组的地方创建数组,从选择、规范化复选框选项等中获取正确的选择选项。如果你想把它转换成JSON(一个真正的JSON字符串),只需JSON.stringify($('form').serializeForm());

评论

0赞 Andrew Barber 12/7/2012
Stack Overflow 不是用来推广你的库的。
3赞 pocesar 12/7/2012
好的,但是 是我库的一部分,并且完全符合 OP 的要求serializeForm
0赞 Alex78191 6/12/2017
最后一个字符串是最好的
0赞 2 revs, 2 users 68%cnizzardini #19

这个解决方案更好。此处的一些更流行的选项在未选中复选框时不会更正处理复选框。

getData: function(element){
//@todo may need additional logic for radio buttons
var select = $(element).find('select');
var input = $(element).find('input');
var inputs = $.merge(select,input);
var data = {};
//console.log(input,'input');
$.each(inputs,function(){
  if($(this).attr('type') != undefined){
    switch($(this).attr('type')){
     case 'checkbox':
        data[$(this).attr('name')] = ( ($(this).attr('checked') == 'checked') ? $(this).val():0 );
        break;
      default:
        data[$(this).attr('name')] = $(this).val();
        break;
    }
  } 
  else {
    data[$(this).attr('name')] = $(this).val();
  }
})
  return data;
}
-8赞 2 revs, 2 users 71%xlthor #20

使用这个:

var sf = $('#mainForm').serialize(); // URL encoded string
sf = sf.replace(/"/g, '\"');         // Be sure all "s are escaped
sf = '{"' + sf.replace(/&/g, '","'); // Start "object", replace tupel delimiter &
sf = sf.replace(/=/g, '":"') + '"}'; // Replace equal sign, add closing "object"

// Test the "object"
var formdata = eval("(" + sf + ")"); 
console.log(formdata);

它就像一个魅力,即使在非常复杂的形式上也是如此。

评论

12赞 Mulan 2/19/2013
用户输入是有风险的 - 任何事情都可能发生。我强烈建议不要这样做。eval
6赞 2 revs, 2 users 88%ngr #21

简单在这里是最好的。我用正则表达式替换了一个简单的字符串,到目前为止,它们就像一个魅力。我不是正则表达式专家,但我敢打赌,您甚至可以填充非常复杂的对象。

var values = $(this).serialize(),
attributes = {};

values.replace(/([^&]+)=([^&]*)/g, function (match, name, value) {
    attributes[name] = value;
});
314赞 mkschreder #22

有什么问题:

var data = {};
$(".form-selector").serializeArray().map(function(x){data[x.name] = x.value;}); 

评论

59赞 sites 6/14/2015
$(this).serializeArray().reduce(function(m,o){ m[o.name] = o.value; return m;}, {})
4赞 Nathan Chappell 8/4/2021
$(this).serializeArray().reduce((o,kv) => ({...o, [kv.name]: kv.value}), {})
0赞 alex 11/26/2021
这是单行解决方案,尽管其他解决方案也有效。
2赞 Adam Fowler 5/19/2022
你的意思是除了这不支持表单数组这一事实之外?
2赞 Jim Stewart #23

要获得快速、现代的解决方案,请使用 JSONify jQuery 插件。以下示例逐字摘自 GitHub README。所有功劳都归功于插件的作者 Kushal Pandya。

鉴于:

<form id="myform">
    <label>Name:</label>
    <input type="text" name="name"/>
    <label>Email</label>
    <input type="text" name="email"/>
    <label>Password</label>
    <input type="password" name="password"/>
</form>

运行:

$('#myform').jsonify();

生产:

{"name":"Joe User","email":"[email protected]","password":"mypass"}

如果要使用此 JSON 对象执行 jQuery POST:

$('#mybutton').click(function() {
    $.post('/api/user', JSON.stringify($('#myform').jsonify()));
}
0赞 2 revs, 2 users 69%Niko #24

我编写了一个jQuery模块jsForm,它甚至可以对相当复杂的表单进行双向操作(也允许集合和其他更复杂的结构)。

它使用字段的名称(加上一些用于集合的特殊类)并匹配 JSON 对象。它允许自动复制 DOM 元素以进行收集和数据处理:

<html>
    <head>
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
        <script src="https://raw.github.com/corinis/jsForm/master/src/jquery.jsForm.js"></script>
        <script>
        $(function(){
            // Some JSON data
            var jsonData = {
                name: "TestName",   // Standard inputs
                description: "long Description\nMultiline", // Textarea
                links: [{href:'http://stackoverflow.com',description:'StackOverflow'}, {href:'http://www.github.com', description:'GitHub'}],   // Lists
                active: true,   // Checkbox
                state: "VISIBLE"    // Selects (enums)
            };

            // Initialize the form, prefix is optional and defaults to data
            $("#details").jsForm({
                data:jsonData
            });

            $("#show").click(function() {
                // Show the JSON data
                alert(JSON.stringify($("#details").jsForm("get"), null, " "));
            });
        });
        </script>
    </head>
    <body>
        <h1>Simpel Form Test</h1>
        <div id="details">
            Name: <input name="data.name"/><br/>
            <input type="checkbox" name="data.active"/> active<br/>
            <textarea name="data.description"></textarea><br/>
            <select name="data.state">
                <option value="VISIBLE">visible</option>
                <option value="IMPORTANT">important</option>
                <option value="HIDDEN">hidden</option>
            </select>
            <fieldset>
                <legend>Links</legend>
                <ul class="collection" data-field="data.links">
                    <li><span class="field">links.description</span> Link: <input name="links.href"/> <button class="delete">x</button></li>
                </ul>
            </fieldset>
            <button class="add" data-field="data.links">add a link</button><br/>
            Additional field: <input name="data.addedField"/>
        </div>
        <button id="show">Show Object</button>
    </body>
</html>
11赞 2 revs, 2 users 82%Adrian Seeley #25

用:

function form_to_json (selector) {
  var ary = $(selector).serializeArray();
  var obj = {};
  for (var a = 0; a < ary.length; a++) obj[ary[a].name] = ary[a].value;
  return obj;
}

输出:

{"myfield": "myfield value", "passwordfield": "mypasswordvalue"}
5赞 4 revs, 2 users 78%G-Ram #26

使用 maček 的解决方案,我对其进行了修改,使其与 MVC 在同一表单上处理嵌套/复杂对象的方式 ASP.NET 工作。您所要做的就是将验证部分修改为:

"validate": /^[a-zA-Z][a-zA-Z0-9_]*((?:\[(?:\d*|[a-zA-Z0-9_]+)\])*(?:\.)[a-zA-Z][a-zA-Z0-9_]*)*$/,

这将匹配并正确映射名称如下的元素:

<input type="text" name="zooName" />

<input type="text" name="zooAnimals[0].name" />

评论

2赞 gre_gor 8/13/2022
这看起来像是对答案的回复,而不是对问题的独立答案。
23赞 2 revs, 2 users 50%olleicua #27

如果你使用的是下划线.js,你可以使用相对简洁的:

_.object(_.map($('#myform').serializeArray(), _.values))

评论

0赞 Aldis 6/25/2022
我不确定它以前是如何工作的,但现在它没有了。更改了一些有效的内容:Object.fromEntries(_.map($('#myform').serializeArray(), _.values))
4赞 2 revs, 2 users 71%Peter Mortensen #28

有一个插件可以为 jQuery 执行此操作,jquery.serializeJSON。我现在已经成功地在一些项目中使用了它。它就像一个魅力。

14赞 3 revs, 3 users 62%Harini Sekar #29

您可以这样做:

var frm = $(document.myform);
var data = JSON.stringify(frm.serializeArray());

请参阅 JSON

评论

0赞 gre_gor 8/13/2022
问题是如何获取对象而不是JSON字符串。
0赞 2 revs, 2 users 67%Harini Sekar #30

如果要发送带有JSON的表单,则必须在发送字符串时删除[]。您可以使用 jQuery 函数 serializeObject() 来做到这一点:

var frm = $(document.myform);
var data = JSON.stringify(frm.serializeObject());

$.fn.serializeObject = function() {
    var o = {};
    //var a = this.serializeArray();
    $(this).find('input[type="hidden"], input[type="text"], input[type="password"], input[type="checkbox"]:checked, input[type="radio"]:checked, select').each(function() {
        if ($(this).attr('type') == 'hidden') { //If checkbox is checked do not take the hidden field
            var $parent = $(this).parent();
            var $chb = $parent.find('input[type="checkbox"][name="' + this.name.replace(/\[/g, '\[').replace(/\]/g, '\]') + '"]');
            if ($chb != null) {
                if ($chb.prop('checked')) return;
            }
        }
        if (this.name === null || this.name === undefined || this.name === '')
            return;
        var elemValue = null;
        if ($(this).is('select'))
            elemValue = $(this).find('option:selected').val();
        else
            elemValue = this.value;
        if (o[this.name] !== undefined) {
            if (!o[this.name].push) {
                o[this.name] = [o[this.name]];
            }
            o[this.name].push(elemValue || '');
        }
        else {
            o[this.name] = elemValue || '';
        }
    });
    return o;
}
70赞 2 revs, 2 users 70%Ethan Brown #31

我喜欢使用,因为它是单行代码,并且不依赖于下划线.js之类的:Array.prototype.reduce

$('#formid').serializeArray()
    .reduce(function(a, x) { a[x.name] = x.value; return a; }, {});

这与使用 的答案类似,但您不需要使用额外的对象变量来混淆您的范围。一站式购物。Array.prototype.map

重要提示:具有重复属性的输入的表单是有效的HTML,实际上是一种常见的方法。在这种情况下,在此线程中使用任何答案都是不合适的(因为对象键必须是唯一的)。name

0赞 2 revstfmontague #32

如果要将表单转换为javascript对象,那么最简单的解决方案(此时)是使用jQuery和函数方法。eachserializeArray

$.fn.serializeObject = function() {

  var form = {};
  $.each($(this).serializeArray(), function (i, field) {
    form[field.name] = field.value || "";
  });

  return form;
};

GitHub 上托管的插件:
https://github.com/tfmontague/form-object/blob/master/README.md

可与 Bower 一起安装:
bower install git://github.com/tfmontague/form-object.git

7赞 3 revs, 3 users 83%juanpastas #33

从一些较旧的答案:

$('form input, form select').toArray().reduce(function(m,e){m[e.name] = $(e).val(); return m;},{})

评论

0赞 davidtgq 5/27/2016
据我所知,区别在于您的解决方案不依赖于,因此您可以自由选择所需的任何输入(例如,您可以包含禁用的输入),对吧?也就是说,这不与任何表单或提交事件耦合,它只是独立于自身?serializeArray
0赞 sites 5/27/2016
与链接答案的唯一小区别是,实例化、返回对象不需要任何数据。这不是独立的,因为它来自 jQuery。reducetoArray
0赞 Max Heiber #34

下面是一种非 jQuery 方法:

    var getFormData = function(form) {
        //Ignore the submit button
        var elements = Array.prototype.filter.call(form.elements, function(element) {
            var type = element.getAttribute('type');
            return !type || type.toLowerCase() !== 'submit';
        });

你可以像这样使用它:

function() {

    var getFormData = function(form) {
        //Ignore the submit button
        var elements = Array.prototype.filter.call(form.elements, function(element) {
            var type = element.getAttribute('type');
            return !type || type.toLowerCase() !== 'submit';
        });

        //Make an object out of the form data: {name: value}
        var data = elements.reduce(function(data, element) {
            data[element.name] = element.value;
            return data;
        }, {});

        return data;
    };

    var post = function(action, data, callback) {
        var request = new XMLHttpRequest();
        request.onload = callback;
        request.open('post', action);
        request.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
        request.send(JSON.stringify(data), true);
        request.send();
    };

    var submit = function(e) {
        e.preventDefault();
        var form = e.target;
        var action = form.action;
        var data = getFormData(form);
        //change the third argument in order to do something
        //more intersting with the response than just print it
        post(action, data, console.log.bind(console));
    }

    //change formName below
    document.formName.onsubmit = submit;

})();
5赞 Roey #35

对于这个问题,我发现的最简单,最准确的方法是使用BBQ插件或这个插件(大约是0.5K字节大小)。

它也适用于多维数组。

$.fn.serializeObject = function()
{
	return $.deparam(this.serialize());
};

评论

0赞 Alf Eaton 4/19/2016
这似乎效果很好。jquery-deparam 还有一个替代存储库,其中包括 bower 和 npm 的描述文件。
-1赞 ceed #36

此函数返回转换为正确类型的所有值;

bool/string/(integer/floats) 可能

为此,您有点需要jQuery,但是由于serializeArray也是jQuery,因此恕我直言,没什么大不了的。

/**
 * serialized a form to a json object
 *
 * @usage: $("#myform").jsonSerialize();
 *
 */

(function($) {
    "use strict";
    $.fn.jsonSerialize = function() {
        var json = {};
        var array = $(this).serializeArray();
        $.each(array, function(key, obj) {
            var value = (obj.value == "") ? false : obj.value;
            if(value) {
                // check if we have a number
                var isNum = /^\d+$/.test(value);
                if(isNum) value = parseFloat(value);
                // check if we have a boolean
                var isBool = /^(false|true)+$/.test(value);
                if(isBool) value = (value!=="false");
            }
            json[obj.name] = value;
        });
        return json;
    }
})(jQuery);
-1赞 2 revs, 2 users 75%Justin Levene #37

创建地图并循环所有字段,保存其值。

var params = {};
$("#form").find("*[name]").each(function(){
    params[this.getAttribute("name")] = this.value;
});
1赞 Ivan Nosov #38

使用 lodash#set

let serialized = [
  { key: 'data[model][id]', value: 1 },
  { key: 'data[model][name]', value: 'product' },
  { key: 'sid', value: 'dh0un1hr4d' }
];

serialized.reduce(function(res, item) {
  _.set(res, item.key, item.value);
  return res;
}, {});

// returns
{
  "data": {
    "model": {
      "id": 1,
      "name": "product"
    }
  },
  "sid": "dh0un1hr4d"
}

评论

0赞 supertrue 4/11/2017
我喜欢这个解决方案,但它不处理数组格式的表单字段; 结果为 。key[][ {key: 'items[]', value: 1 }, {key: 'items[]', value: 2 } ]{ items: { "": 2 } }
25赞 12 revs, 2 users 93%Bhavik Hirani #39

我检查了所有其他答案是否存在问题,如果输入名称为数组,例如 ,则应按如下方式生成:name[key]

name:{ key : value }


例如:如果您有类似于下面的 HTML 表单:

<form>
    <input name="name" value="value" >
    <input name="name1[key1]" value="value1" >
    <input name="name2[key2]" value="value2" >
    <input name="name3[key3]" value="value3" >
</form>

但它应该像下面的 JSON 一样生成,并且不会成为包含所有其他答案的对象。因此,如果有人想带来类似以下 JSON 的东西,请尝试下面的 JS 代码。

{
    name  : 'value',
    name1 : { key1 : 'value1' },
    name2 : { key2 : 'value2' },
    name3 : { key2 : 'value2' }
}

$.fn.getForm2obj = function() {
  var _ = {};
  $.map(this.serializeArray(), function(n) {
    const keys = n.name.match(/[a-zA-Z0-9_]+|(?=\[\])/g);
    if (keys.length > 1) {
      let tmp = _;
      pop = keys.pop();
      for (let i = 0; i < keys.length, j = keys[i]; i++) {
        tmp[j] = (!tmp[j] ? (pop == '') ? [] : {} : tmp[j]), tmp = tmp[j];
      }
      if (pop == '') tmp = (!Array.isArray(tmp) ? [] : tmp), tmp.push(n.value);
      else tmp[pop] = n.value;
    } else _[keys.pop()] = n.value;
  });
  return _;
}
console.log($('form').getForm2obj());
$('form input').change(function() {
  console.clear();
  console.log($('form').getForm2obj());
});
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<form>
  <input name="name" value="value">
  <input type="checkbox" name="name1[]" value="1" checked="checked">1
  <input type="checkbox" name="name1[]" value="2">2
  <input type="checkbox" name="name1[]" value="3">3<br>
  <input type="radio" name="gender" value="male" checked="checked">male
  <input type="radio" name="gender" value="female"> female
  <input name="name2[key1]" value="value1">
  <input name="one[another][another_one]" value="value4">
  <input name="name3[1][name]" value="value4">
  <input name="name3[2][name]" value="value4">
  <input name="[]" value="value5">
</form>

评论

0赞 Leonardo Beal 2/15/2018
这个答案确实涵盖了所提到的情况,但它不包括像 checkbox[] 甚至 one[another][another_one] 这样的情况
1赞 Bhavik Hirani 2/28/2018
@LeonardoBeal我修复了我的 ans..现在检查一下..!
2赞 iRaS 11/27/2019
我不同意这是一个很好的答案。当你写答案时,请让你的代码不言自明或解释它。 简短且无法解释。经验较少的开发人员只会复制它,而不了解它为什么以及如何工作。this.c = function(k,v){ eval("c = typeof "+k+";"); if(c == 'undefined') _t.b(k,v);}
2赞 Bhavik Hirani 5/26/2020
@JackGiffin 立即查看我的新代码,因为我已从代码中删除。eval()
1赞 Burhan Kashour 7/7/2021
@BhavikHirani 经过长时间的搜索,我找到了你的答案,你为我节省了很长时间的搜索时间!谢谢伙计!!
2赞 Folkmann #40

所以我使用了公认的答案,发现了一个重大缺陷。
它不支持以下输入数组:

<input type="checkbox" name="array[]" value="1"/>
<input type="checkbox" name="array[]" value="2"/>
<input type="checkbox" name="array[]" value="3"/>

这个小改动应该可以解决以下问题:

function objectifyForm(inp){
    var rObject = {};
    for (var i = 0; i < inp.length; i++){
        if(inp[i]['name'].substr(inp[i]['name'].length - 2) == "[]"){
            var tmp = inp[i]['name'].substr(0, inp[i]['name'].length-2);
            if(Array.isArray(rObject[tmp])){
                rObject[tmp].push(inp[i]['value']);
            } else{
                rObject[tmp] = [];
                rObject[tmp].push(inp[i]['value']);
            }
        } else{
            rObject[inp[i]['name']] = inp[i]['value'];
        }
    }
    return rObject;
}

请记住将输出传递给它,否则它将无法工作。$(this).serializeArray();

评论

1赞 Nidecker 1/23/2022
是的!这么多赞成的答案,但只有这个答案可以与复选框一起使用。谢谢
15赞 test30 #41

单行代码(除 jQuery 外没有依赖项),对传递给方法的函数使用固定对象绑定。map

$('form').serializeArray().map(function(x){this[x.name] = x.value; return this;}.bind({}))[0]

它有什么作用?

"id=2&value=1&comment=ok" => Object { id: "2", value: "1", comment: "ok" }

适用于渐进式 Web 应用程序(可以轻松支持常规表单提交操作和 Ajax 请求)

4赞 2 revs, 2 users 98%test30 #42

另一个答案

document.addEventListener("DOMContentLoaded", function() {
  setInterval(function() {
    var form = document.getElementById('form') || document.querySelector('form[name="userprofile"]');
    var json = Array.from(new FormData(form)).map(function(e,i) {this[e[0]]=e[1]; return this;}.bind({}))[0];
    
    console.log(json)
    document.querySelector('#asJSON').value = JSON.stringify(json);
  }, 1000);
})
<form name="userprofile" id="form">
  <p>Name <input type="text" name="firstname" value="John"/></p>
  <p>Family name <input name="lastname" value="Smith"/></p>
  <p>Work <input name="employment[name]" value="inc, Inc."/></p>
  <p>Works since <input name="employment[since]" value="2017" /></p>
  <p>Photo <input type="file" /></p>
  <p>Send <input type="submit" /></p>
</form>

JSON: <textarea id="asJSON"></textarea>

FormData:https://developer.mozilla.org/en-US/docs/Web/API/FormData

1赞 user3658510 #43

一种更现代的方法是以这种方式使用 reduce:serializeArray()

$('#formid').serializeArray()
    .reduce((a, x) => ({ ...a, [x.name]: x.value }), {});

这将对许多“正常”情况有所帮助。

对于具有重复属性的多个标签的常见实例,这还不够。name

由于具有重复属性的输入通常位于某个“包装器”(、...)中,如以下示例所示:namedivultr

  <div class="wrapperClass">
    <input type="text" name="one">
    <input type="text" name="two">
  </div>
  <div class="wrapperClass">
    <input type="text" name="one">
    <input type="text" name="two">
  </div>

可以将Reduce与运算符一起使用来迭代它们:map

$(".wrapperClass").map(function () {
  return $(this).find('*').serializeArray()
    .reduce((a, x) => ({ ...a, [x.name]: x.value }), {});
}).get();

结果将是一个对象数组,格式如下:

  [
    {
      one: valueOfOne,
      two: valueOfTwo
    }, {
      one: valueOfOne,
      two: valueOfTwo
    }
  ]

运算符与获取基本数组而不是 jQuery 对象结合使用,后者提供更清晰的结果。jQuery 文档.get()map

6赞 Stonetip #44
const formData = new FormData(form);

let formDataJSON = {};

for (const [key, value] of formData.entries()) {

    formDataJSON[key] = value;
}
1赞 ShQ #45

Javascript / jQuery 单行 - 也适用于旧版本(ES6 之前):

$('form').serializeArray().reduce((f,c) => {f[c['name']]=(f[c['name']])?[].concat(f[c['name']],c['value']):c['value']; return f}, {} );
3赞 2 revs, 2 users 96%Zaz #46

这是使用 reduce 的单行代码。Reduce是一个函数函数,它接受传递的函数的返回值,并在下一次迭代中将其与列表中的第n个值一起传递回传递的函数。

$('#formid').serializeArray().reduce((o,p) => ({...o, [p.name]: p.value}), {})

我们必须使用一些技巧才能使其工作:

  • ...o(spread 语法)插入key: valueo
  • 包装我们返回的对象,以将其与表示函数的对象区分开来(){}
  • 将密钥 () 包装在p.name[]

评论

3赞 Paflow 2/25/2020
如果我不向该函数添加初始化对象,我会得到错误的结果: $('form').serializeArray().reduce((o, p) => ({...o, [p.name]: p.value}), {})
0赞 Zaz 7/4/2023
冥王星已经解决了这个问题。谢谢!
3赞 Arik #47

在一句话中利用 ES6 的优点:

$("form").serializeArray().reduce((o, {name: n, value: v}) => Object.assign(o, { [n]: v }), {});
47赞 2 revs, 2 users 80%aret #48

[2020年更新]

在 vanilla js 中使用一个简单的 oneliner,它利用了 fromEntries(与往常一样,检查浏览器支持):

Object.fromEntries(new FormData(form))

评论

3赞 skilleo 9/13/2021
不将嵌套的表单表示法处理到 JSON 中。
1赞 aret 9/14/2021
显然,由于它不被认为是有效的 html html.spec.whatwg.org/multipage/forms.html#the-form-element,因此即使 chromium 也会删除嵌套形式
0赞 chichilatte 9/28/2021
完美的答案。
3赞 rahman 10/10/2021
非常感谢,😍为扁平模型工作
0赞 Craig Jacobs 8/14/2023
我花了相当多的时间试图让这项工作,以防它能帮助到其他人;确保您的输入具有名称和 ID,并为您的表单命名。以下是返回准备通过 AJAX 发送的 JSON 的整行: const my_form_data = JSON.stringify( Object.fromEntries( new FormData( document.forms.namedItem( “my-form-name” ) ) ) );
0赞 Abd Abughazaleh #49

这段代码对我有用:

  var data = $('#myForm input, #myForm select, #myForm textarea').toArray().reduce(function (m, e) {
            m[e.name] = $(e).val();
            return m;
        }, {});
0赞 2 revsMohsenB #50

此代码转换并保存输入类型,而不是将所有输入转换为字符串:

jQuery.fn.serializeForm = function () {
    var form = this.get(0);
    var i = [];
    var ret = {};
    for (i = form.elements.length - 1; i >= 0; i = i - 1) {
        if (form.elements[i].name === "") {
            continue;
        }
        var name = form.elements[i].name;
        switch (form.elements[i].nodeName) {
            case 'INPUT':
                switch (form.elements[i].type) {
                    case 'text':
                    case 'tel':
                    case 'email':
                    case 'hidden':
                    case 'password':
                        ret[name] = encodeURIComponent(form.elements[i].value);
                        break;
                    case 'checkbox':
                    case 'radio':
                        ret[name] = form.elements[i].checked;
                        break;
                    case 'number':
                        ret[name] = parseFloat(form.elements[i].value);
                        break;
                }
                break;
            case 'SELECT':
            case 'TEXTAREA':
                ret[name] = encodeURIComponent(form.elements[i].value);
                break;
        }
    }
    return ret;
};

例如,这是输出:

Day: 13
Key: ""
Month: 5
OnlyPayed: true
SearchMode: "0"
Year: 2021

而不是

Day: "13"
Key: ""
Month: "5"
OnlyPayed: "true"
SearchMode: "0"
Year: "2021"
-1赞 Steve Moretz #51
function serializedArray2Object(array){
    let obj = {};
    array.forEach(function(item){
        if(obj[item['name']] === undefined){
            obj[item['name']] = item['value'];
        }else if(Array.isArray(obj[item['name']])){
            obj[item['name']] = [...obj[item['name']],item['value']]
        }else{
            obj[item['name']] = [obj[item['name']],item['value']];
        }
    });
    return obj;
}

serializedArray2Object($('#form').serializeArray())

我刚刚从jQuery中发现了该函数,并为对象编写了一个转换器,因此数组变成了一个对象。

0赞 Chris #52

这将处理多个具有相同名称的 select 甚至元素:

$.fn.formToJSON = function(){
    pairStr=this.serialize();
    let rObj={};
    pairStr.split(`&`).forEach((vp)=> {
        prop=vp.split(`=`)[0];
        val=vp.split(`=`)[1];
        if(rObj.hasOwnProperty(prop)) {
            if (Array.isArray(rObj[prop])) {
                rObj[prop].push(val);
            } else {
                rObj[prop]=[rObj[prop]];
                rObj[prop].push(val);
            }
        } else {
            rObj[prop]=val;
        }
    });
    return JSON.stringify(rObj);
}
1赞 Adebayo Vicktor #53

这将使用 foreach 方法循环访问 serializeArray 返回的名称和值对,然后使用名称作为键返回一个对象。

  let formData = $(this).serializeArray();
  let formObject = {}
  formData.forEach(
    x=>formObject.hasOwnProperty(x.name)?formObject[x.name]=[formObject[x.name],x.value].flat():formObject[x.name]=x.value
  );
0赞 BananaAcid #54

这个线程似乎已经成为表单序列化:)的集体常见问题解答

我对PHP命名的看法:<input name="user[name]" >

$('form').on('submit', function(ev) {
   ev.preventDefault();

   var obj = $(this).serializePHPObject();

   // $.post('./', obj);
});
(function ($) {
  // based on https://stackoverflow.com/a/25239999/1644202

  // <input name="user[name]" >
  $.fn.serializePHPObject = function () {
    var obj = {};
    $.each(this.serializeArray(), function (i, pair) {
      var cObj = obj,
        pObj,
        cpName;
      $.each(pair.name.split("["), function (i, pName) {
        pName = pName.replace("]", "");
        pObj = cObj;
        cpName = pName;
        cObj = cObj[pName] ? cObj[pName] : (cObj[pName] = {});
      });
      pObj[cpName] = pair.value;
    });
    return obj;
  };
})(jQuery);
3赞 Zac Fair #55

在不使用 JQuery 的情况下序列化深度嵌套表单

在花了几天时间寻找没有依赖关系的这个问题的解决方案后,我决定使用FormData API制作一个非jQuery表单数据序列化程序。

序列化程序中的逻辑主要基于名为 jQuery BBQ 的 jQuery 插件的 de-param 函数,但是,此项目中的所有依赖项都已删除。

这个项目可以在 NPM 和 Github 上找到:

https://github.com/GistApps/deep-serialize-form

https://www.npmjs.com/package/deep-serialize-form

function deepSerializeForm(form) {

  var obj = {};

  var formData = new FormData(form);

  var coerce_types = { 'true': !0, 'false': !1, 'null': null };

  /**
   * Get the input value from the formData by key
   * @return {mixed}
   */
  var getValue = function(formData, key) {

    var val = formData.get(key);

    val = val && !isNaN(val)              ? +val              // number
        : val === 'undefined'             ? undefined         // undefined
        : coerce_types[val] !== undefined ? coerce_types[val] // true, false, null
        : val;                                                // string

    return val;
  }

  for (var key of formData.keys()) {

    var val  = getValue(formData, key);
    var cur  = obj;
    var i    = 0;
    var keys = key.split('][');
    var keys_last = keys.length - 1;


    if (/\[/.test(keys[0]) && /\]$/.test(keys[keys_last])) {

      keys[keys_last] = keys[keys_last].replace(/\]$/, '');

      keys = keys.shift().split('[').concat(keys);

      keys_last = keys.length - 1;

    } else {

      keys_last = 0;
    }


    if ( keys_last ) {

      for (; i <= keys_last; i++) {
        key = keys[i] === '' ? cur.length : keys[i];
        cur = cur[key] = i < keys_last
        ? cur[key] || (keys[i+1] && isNaN(keys[i+1]) ? {} : [])
        : val;
      }

    } else {

      if (Array.isArray(obj[key])) {

        obj[key].push( val );

      } else if (obj[key] !== undefined) {

        obj[key] = [obj[key], val];

      } else {

        obj[key] = val;

      }

    }

  }

  return obj;

}

window.deepSerializeForm = deepSerializeForm;

评论

0赞 PaPaFox552 3/31/2023
Uncaught TypeError: FormData constructor: Argument 1 does not implement interface HTMLFormElement.我不明白
0赞 Dharmendrasinh Chudasama #56

这将与您想要的完全相同

  • 以下代码仅执行一次
$.fn.serializeObject = function(){
    let d={};
    $(this).serializeArray().forEach(r=>d[r.name]=r.value);
    return d;
}
  • 现在,您可以执行以下行任意次数
let formObj = $('#myForm').serializeObject();
// will return like {id:"1", username:"abc"}

评论

0赞 PaPaFox552 3/31/2023
如果表单包含同名输入字段,则仅返回最后一个字段,则 =/
1赞 zwcloud #57

对于 semantic-ui/fomantic-ui,有一个内置行为:get values

const fields = $("#myForm.ui.form").form('get values');
const jsonStr = JSON.stringify(fields);

查看 https://fomantic-ui.com/behaviors/form.html#/settings

获取值(标识符)返回与标识符数组匹配的元素值的对象。如果未传递 IDS,将返回所有字段

0赞 dazzafact #58

这将考虑到一切

  function formToObject(form) {
    
    
    let data = new FormData(form);
    let queryString = new URLSearchParams(data).toString();
      var obj = {};
      var params = queryString.split("&");
      for (var i = 0; i < params.length; i++) {
        var param = params[i].split("=");
    
         var key = param[0].replace("[]", "");
         var key = key.replace("%5B%5D", "");
         
        var value = param[1];
        if (obj[key] === undefined) {
          obj[key] = value;
        } else if (obj[key] instanceof Array) {
          obj[key].push(value);
        } else {
          obj[key] = [obj[key], value];
        }
      }
      console.log(obj)
      return obj;
    }
  <!DOCTYPE html>
<html>
  <head>
    <title>Form Example</title>
  </head>
  <body style="height:800px;overflow:scroll">
    <form id="test" onchange="formToObject(this)"><div><h3>fruits</h3>
    <input type="checkbox" name="fruit" value="apple" id="apple">
<label for="apple">Apfel</label>

<input type="checkbox" name="fruit" value="banana" id="banana">
<label for="banana">Banane</label>

<input type="checkbox" name="fruit" value="cherry" id="cherry">
<label for="cherry">Kirsche</label>

<input type="checkbox" name="fruit" value="grape" id="grape">
<label for="grape">Traube</label>

<input type="checkbox" name="fruit" value="pear" id="pear">
<label for="pear">Birne</label></div>
<div><h3> multiple options</h3>
   
      <select multiple name="manyOptions[]">
        <option value="Option 1">Option 1</option>
        <option value="Option 2">Option 2</option>
        <option value="Option 3">Option 3</option>
      </select>
    </div>
    <div><h3> Check on option</h3>
      <input type="radio" name="onceOption" value="Option 1">Option 1<br>
      <input type="radio" name="onceOption" value="Option 2">Option 2<br>
      <input type="radio" name="onceOption" value="Option 3">Option 3<br>
   
   </div></form>
  </body>
</html>