序列化表单数据

在前公司的项目里,遇到过一个需求,需要将整个表单的数据提出来序列化成字符串,然后使用AJAX来
提交数据,
当时凭着经验写了一个,工作的还不错,没有出现过问题,现在想来,当时写的很不严谨,我缺少了很
多验证和测试的步骤,最明显的一点是,我甚至说不清到底哪些表单控件的值才是真正会被提交的>_<.

所以一个详细的测试是不可缺少的,我写了一个放置了所有表单元素的页面,使用fiddler监控了提交的数据,测试结果如下:

注:在这个测试中,我并没有选择文件进行上传,而是直接点击了submit按钮。

从图中我们可以看到浏览器们只对两个地方存在分歧:

1.只有 IE6,IE7 都会提交<button></button>的value
2.而Chrome则没有提交<input type="file" />

第2个分歧在进一步测试时被纠正,Chrome的处理方式是,如果你不选择文件,那么就不提交file域的
名字和值,否则才会提交.
而第1个则非常奇怪,其他浏览器似乎都无视了<button>,只有ie给于了关注,而通过查资料,我得到
更多的信息:

当 BUTTON 元素在表单中提交的话,Microsoft® Internet Explorer 5 及以后版本将提交 VALUE 标签
属性,
若存在的话。否则就提交 innerText 属性。在 Internet Explorer 4.0 中,只会提交 innerText 值
(这个结果非常有趣,所以你的button最好别加name属性,否则可能会提交很多数据)

知道了具体会上传啥东西,本着节省传输数据量的精神,我们就可以做个总结。


首先button是要被干掉的,因为其他浏览器均不支持,放上去也只是浪费字节
file域我们可以采用Chrome的处理方式,只有选择文件后才会被提交,但是AJAX无法上传文件,所以实际上file域没有意义,可以不提交
radio组和checkbox组同上,一组中有一个(或多个)被选中的值会被提交,如果一个也没选中,都不
会被提交
select只提交选中的值,如果没有一个选中的,那么提交第一项
select multiple 只提交选中的值,如果没有一个选中的,那么不会被提交
其余的控件不管有没有值都会被提交


剩下需要的提交的就是
<input type="text" />
<input type="password" />
<input type="hidden" />
<input type="submit" />

<input type="radio" /> //选择选中的
<input type="checkbox" />//选择选中的
<input type="file" />

<select></select>
<select multiple></select>
<textarea></textarea>

最后就是需要给所有的值做转义,有能力给这个表单序列化结果附加更多的数据

我的实现如下:

 ExpandedBlockStart.gif代码

 1  function  FormDataSerialize( form  /* HTMLFormElement */ ,attachParams  /*  Object  */  )
 2 
 3       var  encode  =  encodeURIComponent, 
 4      currCon, 
 5      currTag, 
 6      currVal,    
 7      currType, 
 8      currName,    
 9      currOpts, 
10      currOpt,
11      temp,
12      result    =  [], 
13      els       =  form.elements, 
14      iTypeReg  =   / ^checkbox|radio$ / i, 
15      bTypeReg  =   / ^button|reset|image$ / i,
16      A  =  Array;
17 
18       for var  l  =  els.length; l -- ;  )
19      {
20          currCon    =  els[ l ];
21          currTag    =  currCon.tagName.toLowerCase();
22          currType   =  currCon.type;
23          currVal    =  currCon.value;
24          currName   =  currCon.name;    
25          
26           if ( currTag  ==   ' button '   ||     // 如果是button,忽略掉                 
27              ( iTypeReg.test( currType )  &&  currCon.checked  ===   false  )   ||   // 如果是radio或checkbox,而且checked为false,忽略掉
28              ( bTypeReg.test( currType )  ||   // 如果是type=button,type=reset,type=image的控件,忽略掉
29              ( currType  ==   ' file '  ) )   // 如果是file域 ,忽略掉            
30          )  continue ;  
31 
32           if ( currCon.multiple  ===   true   &&  currType  ==   ' select-multiple '  )  // 如果是多选框,遍历options特殊处理
33          {
34              currOpts  =  currCon.options;
35               for var  m  =  currOpts.length; m -- ;  )
36                  ( currOpt  =  currOpts[m] ).selected  &&  
37                  ( result.push( encode( currName )  +   ' = '   +  encode( currOpt.value ) ) );
38               continue ;
39          }
40 
41           // 其余的只需要取value就好
42          result.push( encode( currName )  +   ' = '   +  encode( currVal ) );
43      }
44      
45       // 处理附加的数据
46       for var  item  in  attachParams )
47      { 
48           if ( ( temp  =  attachParams[ item ] )  instanceof  A )   // 数组使用多选框处理方式
49               for ( l  =  temp.length; l --  ; ) result.push( encode( item )  +   ' = '   +  encode( temp[l] ) );
50           else  result.push( encode( item )  +   ' = '   +  encode( temp ) );  // 其余直接取key=value就好
51      } 
52      
53       // 最后加上分隔符的&
54       return  result.join( ' & ' );
55  }

 

 

 使用方式:

1  var  dataStr  =  FormDataSerialize( document.getElementById(  ' myForm '  ),
2  {
3      username :  ' wait ' ,
4      password :  ' 123456789 ' ,
5      keys     : [  1 , 2 , 3 , 4 , 5  ]
6  });

 

 


OK,函数基本上就是这个样子了,还有有些可以改进的地方,比如 attachParams 可以接受string类型的。

上面也说了,这个函数一般都用在AJAX提交数据上。显然这个需求很旺盛,于是Firefox在版本4内置了一个 FormData 对象.

它4这样子用滴:

ExpandedBlockStart.gif 代码
1  var  formData  =   new  FormData();
2  formData.append( " username " " Groucho " );
3  formData.append( " accountnum " 123456 );
4  formData.append( " afile " , fileInputElement.files[ 0 ]);
5 
6  xhr.open( " POST " " http://foo.com/submitform.php " );
7  xhr.send(formData);

 

 不但可以无中生有,还可以直接从form对象导出FormData对象:

1  var  formElement  =  document.getElementById( " myFormElement " );
2  formData  =  formElement.getFormData();
3  formData.append( " serialnumber " , serialNumber ++ );
4  xhr.send(formData);

 

 看起来真的很好用蛤,但是,比较恶心银的是它不会被转换成字符串,formData本身就是一个对象,也只能用在AJAX的send方法里。


FormData参考:

https://developer.mozilla.org/en/XMLHttpRequest/FormData

https://developer.mozilla.org/En/XMLHttpRequest/Using_XMLHttpRequest#Using_FormData_objects

 

 2009/7/9 update:

今天对FormData做了一些更详细的测试,原来FromData并不是像我想象的那样, 它的存在主要是为了解决上传文件的问题,也就是说,

如果你的表单中有许多控件,包括文件域,这时候你想同时用AJAX提交这些混合内容, 就可以使用FormData了(可以用AJAX上传文件已经是一个惊喜了)。

 

FormData 要求表单必须使用 method="post" enctype="multipart/form-data"  (GET是无效的,什么也不会被传递)

而且FormData传递的数据也完全跟表单正常post一模一样,类似如下:

 

-----------------------------29962268197975

Content-Disposition: form-data; name="input-text"

text-value

-----------------------------29962268197975

Content-Disposition: form-data; name="input-hidden"

hidden-value

-----------------------------29962268197975

Content-Disposition: form-data; name="input-password"

password

-----------------------------29962268197975

Content-Disposition: form-data; name="input-radio-group"

radio-group-4

  

看来是我高兴早了,FormData是没有办法完全代替FormDataSerialize函数的功能的。

 

 

转载于:https://www.cnblogs.com/waitcat/archive/2010/07/09/1774043.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值