什么是表单序列化呢?

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

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

  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];即可,其他不动。

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

分类: JavaScript 标签: 对象文件data代码text东西alert元素functionvartypeo

评论

全部评论 2

  1. Alex
    Alex
    Google Chrome Windows 7
    你好,很佩服你的毅力,我也是自学js基础,看了不少视频,最后看的李炎恢JS封装项目。我也是跟着做了一半最后我放弃了。目前正在学习前端框架angular和后端的node.js.加油。。前端涉及的东西很多。希望有机会可以互相分享和学习。
    1. 木灵鱼儿
      木灵鱼儿
      FireFox Windows 10
      @Alex我也是看李炎恢这个,但是感觉学了很多其实忘了也很多,js我估计还要再看看一些基础教程和项目实践才行

目录