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

Posted

技术标签:

【中文标题】使用 jQuery 将表单数据转换为 JavaScript 对象【英文标题】:Convert form data to JavaScript object with jQuery 【发布时间】:2010-11-14 03:39:50 【问题描述】:

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

我想通过某种方式从我的表单中自动构建一个 JavaScript 对象,而不必遍历每个元素。我不想要 $('#formid').serialize(); 返回的字符串,也不想要 $('#formid').serializeArray(); 返回的地图

【问题讨论】:

因为第一个返回一个字符串,就像您使用 GET 方法提交表单时得到的一样,第二个给您一个对象数组,每个对象都有一个名称值对。我希望如果我有一个名为“email”的字段,我会得到一个对象,该对象将允许我使用 obj.email 检索该值。使用 serializeArray(),我必须做类似 obj[indexOfElement].value 的事情 【参考方案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;

【讨论】:

【参考方案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;
);

【讨论】:

难道不能通过先将 XSS 攻击转换为 JS 对象而不是直接转换为字符串来规避 XSS 攻击吗?【参考方案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;

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

【讨论】:

你的意思是“为什么首先使用serializeArray来获取数据?”因为 serializeArray 已经编写好了,在多个浏览器中进行了单元测试,理论上可以在以后的 jQuery 版本中进行改进。您编写的需要直接访问 DOM 元素等不一致事物的代码越少,您的代码就越稳定。 请注意,serializeArray() 不会包含禁用的元素。我经常禁用与页面上其他元素同步的输入元素,但我仍然希望它们包含在我的序列化对象中。如果需要包含禁用元素,最好使用 $.map( $("#container :input"), function(n, i) /* n.name and $(n).val() */ ); 之类的东西。【参考方案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 中测试。

【讨论】:

【参考方案5】:

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

这是我来自other SO question的回答:

最初,我们使用 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);

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

【讨论】:

我在一个项目中尝试过,像这样使用map 创建了一个具有单个属性的对象数组,它不会将所有属性折叠到一个对象中。【参考方案6】:

我发现 Tobias Cohen 的代码存在问题(我没有足够的分数直接评论它),否则它对我有用。如果你有两个同名的选择选项,都带有 value="",那么原始代码将产生 "name":"" 而不是 "name":["",""]

我认为这可以通过在第一个 if 条件中添加“|| o[this.name] == ''”来解决:

$.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;
;

【讨论】:

【参考方案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

【讨论】:

【参考方案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?)
);

【讨论】:

【参考方案9】:

我喜欢 samuels 版本,但我相信它有一个小错误。通常 JSON 被发送为

"coreSKU":"PCGUYJS","name_de":"whatever",...

不是

["coreSKU":"PCGUYJS","name_de":"whatever",...

所以函数 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' ) )

对于 stringify,请查看 Question 3593046 以获得精益版本,查看 json2.js 以获得涵盖所有可能性的版本。这应该涵盖所有内容:)

【讨论】:

谢谢你..这(正如你提到的)微小但非常重要的区别。【参考方案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等。

【讨论】:

【参考方案11】:

序列化函数以JSON对象为参数,返回序列化字符串。

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

【讨论】:

【参考方案12】:

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


当前来源是on GitHub和Bower。

$ bower install 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);

【讨论】:

所以,效果很好。但它命名错误:顾名思义,它不返回 JSON。相反,它返回一个对象字面量。此外,检查 hasOwnProperty 也很重要,否则您的数组有任何附加到其原型的东西,例如:numbers: ["1", "3", indexOf: function()...]【参考方案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  

【讨论】:

【参考方案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;
;

【讨论】:

您似乎没有阅读我的全部评论。我设计了一个处理foo[bar]-type 输入以及foo[bar][bof][a][b][c][etc] 的解决方案;在此线程中查看我的答案。另请注意,foo[bar]“解析”不是 PHP 独有的。 Rails 严重依赖这种约定来将表单属性传递给对象。【参考方案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;
;

【讨论】:

【参考方案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;

【讨论】:

【参考方案17】:

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

关键是您可能实际上想要构建一个表单,以便它本身具有结构,所以假设您想要创建一个表单,用户可以在其中插入他最喜欢的城镇地点:您可以想象这个表单代表一个@ 987654327@ XML 元素包含用户喜欢的地点列表,因此是&lt;place&gt;...&lt;/place&gt; 元素列表,每个元素包含例如&lt;name&gt;...&lt;/name&gt; 元素、&lt;type&gt;...&lt;/type&gt; 元素,然后是&lt;activity&gt;...&lt;/activity&gt; 元素列表,以表示您的活动可以在这样的地方表演。所以你的 XML 结构应该是这样的:

<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-like 数据库中 从您的 $_POST[] 服务器端读取它并检索一个正确嵌套的数组,然后您可以对其进行语义操作 使用一些服务器端脚本将其转换为格式良好的 XML 文件(即使您不知道它的确切结构先验) 以某种方式在任何Node.js-like 服务器脚本中使用它

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

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

这就是&lt;fieldset&gt; 标签派上用场的地方!我们将使用&lt;fieldset&gt; 标签来表示我们的表单/XML 表示中的所有容器元素,因此得到如下结果:

<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'

            ]

        ,

        ...,

        ...

    ]


为此,我开发了this jQuery plugin here,有人帮助优化了this Code Review thread,看起来像这样:

$.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;
;

我还发了this one blog post 来解释更多。

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

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

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

我希望这对某人有帮助!

【讨论】:

你想做什么?【参考方案18】:

我的库 phery 中的代码有一个序列化例程,可以处理非常复杂的表单(如演示中的 https://github.com/pocesar/phery/blob/master/demo.php#L1664 ),它不是一刀切的。它实际上检查每个字段的类型。例如,单选框与范围不同,与 keygen 不同,与选择多个不同。我的功能涵盖了一切,你可以看到 在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;

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

【讨论】:

Stack Overflow 不适合你宣传你的图书馆。 好的,但 serializeForm 是我的库的一部分,并且完全符合 OP 的要求 最后一串最好【参考方案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;
   

【讨论】:

【参考方案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);

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

【讨论】:

eval 用户输入是有风险的 - 任何事情都可能发生。我强烈建议不要这样做。【参考方案21】:

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

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

values.replace(/([^&]+)=([^&]*)/g, function (match, name, value) 
    attributes[name] = value;
);

【讨论】:

【参考方案22】:

有什么问题:

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

【讨论】:

$(this).serializeArray().reduce(function(m,o) m[o.name] = o.value; return m;, ) $(this).serializeArray().reduce((o,kv) =&gt; (...o, [kv.name]: kv.value), ) 这是单行解决方案,但其他解决方案也可以。【参考方案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":"joe@example.com","password":"mypass"

如果你想用这个 JSON 对象做一个 jQuery POST:

$('#mybutton').click(function() 
    $.post('/api/user', JSON.stringify($('#myform').jsonify()));

【讨论】:

【参考方案24】:

我自己编写了一个多维 JavaScript 对象的表单,以便在生产中使用它。结果是https://github.com/serbanghita/formToObject.js。

【讨论】:

我在一个非常具体的实现中使用了这个的变体,非常感谢! 感谢您让我知道它很有用。我有一些即将推出的功能要推出,这会激励我。【参考方案25】:

我编写了一个 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://***.com',description:'***', 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>

【讨论】:

【参考方案26】:

用途:

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"

【讨论】:

【参考方案27】:

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

"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" />

【讨论】:

【参考方案28】:

如果你使用Underscore.js可以使用比较简洁的:

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

【讨论】:

【参考方案29】:

有一个插件可以为 jQuery 做到这一点,jquery.serializeJSON。我现在已经在一些项目上成功地使用了它。它就像一个魅力。

【讨论】:

【参考方案30】:

你可以这样做:

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

JSON

【讨论】:

以上是关于使用 jQuery 将表单数据转换为 JavaScript 对象的主要内容,如果未能解决你的问题,请参考以下文章

在表单上使用 jquery 日期选择器将用户输入转换为整数日期

jQuery将.serialize()数据转换为JSON数据

将 asp.net 表单“转换”为 html 表单

如何将 jQuery UI 控件转换为表单元素契约?

Jquery 将 " 转换为文字引号

jQuery序列化将所有空格转换为加号