首页 » JavaScript » Ajax 表单序列化

最后更新于 2019年03月06日

什么是表单序列化呢?

将所有表单的提交通过一个标准化的方法去获取并且提交出去,那就是序列化,也就是说不同的表单,如注册啊,登录啊,修改资料啊,这些东西可以通过一个通用的方法去处理它。

那么表单序列化有几个要求:

  1. 不能发送禁用的表单字段;
  2. 只发送勾选的复选框和单选按钮;
  3. 不发送type是reset、submit、file、button以及字段集;
  4. 多选选择框中的每个选中的值单独一个条目;
  5. 对于select元素,如果有value值,就指定value作为发送的字段,如果没有,就指定text值;

已经将ajax的代码作为单独的一个文件保存,而调用则使用ajax()的方法,之前也做了一个表单提交的方法,在所有条件都是ture的时候才调用 submit()方法提交表单,但是我们使用ajax表单序列化则不使用这个方法,而是使用ajax()方法来提交;

if (flage) {
    ajax({
        method: 'post',
        url: 'demo3.php',
        data: $('#reg_form').serialize(),
        success: function(text) {
            alert(text);
        },
        async: true
    });
}

data的值则是获取到表单提交的字段,并转为键值对的对象保存,然后ajax提交出去。

$('#reg_form').serialize() 这句就是获取到表单里面的内容的,方法则是使用serialize方法,这里我是直接写的固定id,实际上应该要通过方法来获取当前表单的,这里以后再说。

那先写serialize的方法

function serialize(form) {
  var pre = {};
  for(var i = 0;i<form.elements.length;i++){
    var filed = form.elements[i];
    switch(filed.type) {
      case undefined :
      case 'reset' :
      case 'submit' :
      case 'file' :
      case 'button' :
        break;
      case 'radio' :
      case 'checkbox'
        if(!filed.selected) break;
      default :
        pre[filed.name] = filed.value;
    }
  }
  return pre;
}

这里传入的form就是表单元素,pre就是创建的一个空对象,用来保存键值对,通过for循环,将表单里面的元素一个个判断,通过switch方法判断,如果是当前元素的type值是undefined,说明当前元素被禁用,如果是reset、submit、file、button,这几个共用一个break,如果是radio和checkbox共用一个if(!filed.selected) break; 反之以上都不是,说明是可以正常获取到值的,通过pre[filed.name] = filed.value;的方式,将name和value保存在pre对象中。

但是这里还差一个select元素,这个元素有两种type值,一种是单选的,如问题,年月日这些都是单选的,他的type值为select-one,那如果是多选的,type值为select-multiple;既然都是select元素,那么也可以共用同一个方法,加上都是选项,自然会有个多个选项,for循环肯定要有

case 'select-one' :
case 'select-multiple' :
  for(var j = 0;j<filed.options.length;j++) {
    var option = filed.options[j];
    if(option.selected){
      var opValue = '';
      if(option.hasAttrbute) {
        opValue = option.hasAttrbute('value') ? option.value : option.text;
      }else {
        opValue = option.attributes('value').specified ? option.value : option.text;
      }
      pre[filed.name] = opValue;
    }
  }

for循环一遍select中的所有option元素,如果这个option被选择了(option.selected),那么就判断,这个元素有没有value值,如果有,返回value值,如果没有,返回text值。

一般来说,value是通用属性,一般都是返回input元素中用户填入的值,但是选项就不一样了,选项是固定的值,value的值一般都是事先写在html上的,但也有可能没有写。

text属性是option元素的属性,返回的是设置的值:

<option>我就是text属性获得的值</option>

value的值我们有可能没有设置,那么就要获得text的值,但是ie和其他浏览器没有一个可以通杀的方法来判断到底设没设置value的值,所以还要做个兼容。

hasAttrbute这个方法是ie8及以上和其他浏览器支持,attributes是旧方法,它单独使用:option.hasAttrbute;这样是获取option元素里面所有的属性集合,option.hasAttrbute(‘value’);这样则是单独获取value的属性,再通过specified来判断value是否有值,如果没有,则返回text。

value和text的属性所有浏览器都是支持的,只是判断value是否有值,旧版本ie就不能使用hasAttrbute来判断。

判断好后,将值赋给opValue,然后在传给pre对象。

整合一下:

function serialize(form) {
    var pre = {};
    for (var i = 0; i < form.elements.length; i++) {
        var filed = form.elements[i];
        switch (filed.type) {
            case undefined:
            case 'reset':
            case 'submit':
            case 'file':
            case 'button':
                break;
            case 'radio':
            case 'checkbox'
            if (!filed.selected) break;
            case 'select-one':
            case 'select-multiple':
                for (var j = 0; j < filed.options.length; j++) {
                    var option = filed.options[j];
                    if (option.selected) {
                        var opValue = '';
                        if (option.hasAttrbute) {
                            opValue = option.hasAttrbute('value') ? option.value : option.text;
                        } else {
                            opValue = option.attributes('value').specified ? option.value : option.text;
                        }
                        pre[filed.name] = opValue;
                    }
                }
            default:
                pre[filed.name] = filed.value;
        }
    }
    return pre;
}

调用:


serialize($('#reg_form').first());

这样就差不多了,我们再将他整合成一个插件,之前的插件入口是:

//插件入口
Base.prototype.extend = function(name,fn) {
    Base.prototype[name] = fn;
}

于是:

//表单序列化
 $().extend('serialize',function(){
     for(var i = 0;i<this.arr.length;i++) {
        var form = this.arr[i];
        var pre = {};
        for(var i = 0;i<form.elements.length;i++){
            var filed = form.elements[i];
            switch(filed.type){
                case  undefined :
                case 'submit' :
                case 'reset' :
                case 'file' :
                case 'button' :
                    break;
                case 'radio' :
                case 'checkbox' :
                    if (!filed.selected) break;
                case 'select-one' :
                case 'select-multiple' :
                    for(var j = 0;j<filed.options.length;j++){
                        var option = filed.options[j];
                        if(option.selected) {
                            var opValue = '';
                            if(option.hasAttribute) {
                                opValue = option.hasAttribute('value') ? option.value : option.text;
                            }else {
                                opValue = option.attributes('value').specified ? option.value : option.text;
                            }
                            pre[filed.name] = opValue;
                        }
                    }
                default :
                        pre[filed.name] = filed.value;
            }    
        }
        return pre;        
     }
     return this;
});

form元素不用通过传参的方式获取,而是通过this.arr[i]的方式获取到了,所以做个一个var form = this.arr[i];即可,其他不动。

调用方法则和开头写的一样,这里就不重复了。

  • weixiao kaixin tushetou jingkong deyi fanu liezui liuhan daku ganga bishi nanguo lihai qian yiwen numu tu yi haixiu se fadai minyan hehe henkaixin huaji biyiyan kuanghan maimeng shui xiaku penqi zhangzui pen aini ye niu laji ok chigua renshi kongbu shuai xiaoxiese touxiao huaixiao jingnu chihuai kaisang xiaoku koubi zhuangbi lianhong kanbujian shafa zhijing xiangjiao dabian yaowan redjing lazhu rizhi duocang chixigua hejiu xixi xiaopen goukun xiaobuchu shenme wusuowei guancha lajing chouyan xiaochi bie zhadanzui zhadanxiao
  1. Alex

    发表于:
    来自 Google Chrome 68 in windows 7

    你好,很佩服你的毅力,我也是自学js基础,看了不少视频,最后看的李炎恢JS封装项目。我也是跟着做了一半最后我放弃了。目前正在学习前端框架angular和后端的node.js.加油。。前端涉及的东西很多。希望有机会可以互相分享和学习。

    回复
    1. 木灵鱼儿

      发表于:
      来自 Google Chrome 72.0.3626.109 in Windows 10
      @Alex

      我也是看李炎恢这个,但是感觉学了很多其实忘了也很多,js我估计还要再看看一些基础教程和项目实践才行

      回复