# 表单处理
[TOC]
## 表单介绍
在HTML中,表单是由<form>元素来表示的,而在JavaScript中,表单对应的则是HTMLFormElement类型。HTMLFormElement继承了HTMLElement,因此它拥有HTML元素具有的默认属性,并且还独有自己的属性和方法:
* `acceptCharset` 服务器能够处理的字符集
* `action` 接受请求的URL
* `elements` 表单中所有控件的集合
* `enctype`请求的编码类型
* `length` 表单中控件的数量
* `name` 表单的名称
* `target` 用于发送请求和接受响应的窗口名称
* `reset()` 将所有表单重置
* `submit()` 提交表单
## 获取表单
`<form>`对象的方法有很多种,如下:
* `document.getElementById('myForm');` //使用ID获取<form>元素
* `document.getElementsByTagName('form')[0];`//使用获取第一个元素方式获取
* `document.forms[0]; ` //使用forms的数字下标获取元素
* `document.forms['yourForm'];` //使用forms的名称下标获取元素
* `document.yourForm;` //使用name名称直接获取元素(不推荐)
> PS:最后一种方法使用name名称直接获取元素,已经不推荐使用,这是向下兼容的早期用法。问题颇多,比如有两个相同名称的,变成数组;而且这种方式以后有可能会不兼容。
## 提交表单
通过事件对象,可以阻止submit的默认行为,submit事件的默认行为就是携带数据(默认以get方式)跳转到指定页面(默认为本页)。
```
addEvent(fm, 'submit', function (evt) { //注意是在form对象上触发submit事件
preDef(evt);
});
```
> PS:submit事件,用传统的方式:fm.onsubmit = function () {}。
> PS:必须把submit事件绑定到form对象上,才可以触发submit事件,只不过触发submit事件的流程是点击input中的submit按钮而已。
> PS:在表单中尽量避免使用name="submit"或id="submit"等命名,这会和submit()方法发生冲突导致无法提交。
## 表单阻塞问题
提交数据最大的问题就是重复提交表单。因为各种原因,当一条数据提交到服务器的时候会出现延迟等长时间没反映,导致用户不停的点击提交,从而使得重复提交了很多相同的请求,或造成错误、或写入数据库多条相同信息。
有两种方法可以解决这种问题:
* 第一种就是提交之后,立刻禁用点击按钮;
```javascript
document.getElementById('sub').disabled = true;
```
* 第二种就是提交之后取消后续的表单提交操作。
```javascript
var fm = document.getElementById('myForm');
var flag = false; //设置一个监听变量
addEvent(fm, 'submit', function(evt) {
preDef(evt);
if (flag == true) return; //如果存在返回退出事件
flag = true; //否则确定是第一次,设置为true,表示我提交过一次了
alert('提交');
setTimeout(function() {
fm.submit();
}, 3000);
})
```
## 重置表单
用户点击重置按钮时,表单会被初始化。虽然这个按钮还得以保留,但目前的Web已经很少去使用了。因为用户已经填写好各种数据,不小心点了重置就会全部清空,用户体验极差。
有两种方法调用reset事件:
* 第一个就是直接`type="reset"`即可;
* 第二个就是使用`fm.reset()`方法调用即可。
## 表单字段
如果想访问表单元素,可以使用之前章节讲到的DOM方法访问。但使用原生的DOM访问虽然比较通用,但不是很便利。表单处理中,我们建议使用HTML DOM,它有自己的elements属性,该属性是表单中所有元素的集合。
> PS:表单控件是什么? form里面的input,submit,textarea,select 这些叫做表单控件,其实就是表单元素标签,通过表单元素集合获取第一个元素,非表单控件会被忽略掉。
* `fm.elements[0];` //获取第一个表单字段元素
* `fm.elements['user'];` //获取name是user的表单字段元素
* `fm.elements.length;` //获取所有表单字段的数量
如果多个表单字段都使用同一个name,那么就会返回该name的NodeList表单列表。
fm.elements['sex']; //获取相同name表单字段列表
##使用ajax提交表单
此处使用到`jquery` or `zepto`
$ 使用`serialize()`,`serializeArray()`方法取得表单数据+字符串和对象类型
原始form表单值获取方式(手动):
```javascript
$.ajax({
type: "POST",
url: "api.php",
data: "Name=xiaoming&age=12",
success: function(msg){alert(msg);},
error: function(error){alert(error);}
});
```
serialize()方法取值:
```javascript
$.ajax({
type: "POST",
url:"ajax.php",
data:$('#formID').serialize(),// 也可以使用serializeArray,要提交的表单
success: function(msg) {alert(msg);},
error: function(error){alert(error);}
});
```
> 如果明确了是POST方法可以使用 `$.post(url,[data],[success])`方法,如果是GET可使用`$.get(url,[data],[succes])`
关于jquery的ajax请求详细介绍可以参考了(http://hemin.cn/jq/jQuery.ajax.html)
## 我们的开发规范
1. 明确需求
项目开始前,如果项目需要后端参与,需要明确项目需求.如表单的可选字段,必填字段,表单提交次数等详细需求
2. 前端数据验证
如果表单中有些字段明显不合法,前端需要检查过滤,并提示用户重新输入,如果直接提交会造成响应较慢,用户体验就比较差,而且影响服务器处理效率(数据在后端也会进行二次校检,保证数据合法性和安全性)
3. 与后端约定接口和返回数据类型
前端与后端约定字段类型,如姓名(`username`),年龄(`age`)
前后端工作需要明确,后端负责数据的处理与存储,并返回处理结果给前端,前端需要根据返回结果反馈给用户
举例:提交一个姓名和年龄的流程
```html
<script>
var api = 'http://wx.diggid.cn/api/ajax/success';//前后端约定数据的提交接口,等后端完成工作后只需要提供给前端此接口即可
</script>
<!-- 表单的基本属性-->
<form name="userinfo" id="myform" method="POST">
<div id="error"></div>
<input name="username" type="text" placeholder="请输入您的姓名" />
<input name="age" type="number" placeholder="请输入年龄" />
<button type="button" id="send-form">提交数据</button>
</form>
```
//js处理部分
```javascript
var form = $('#myform');
$('#send-form').click(function(){
//数据验证
var username = form.find('[name="username"]').val();
if(username.length < 2) return alert('请输入您的名字,两个汉字以上');
if(username.length > 12) return alert('您的名字太长了,请保持在12字符以内');
var age = form.find('[name="age"]').val();
if(age < 0 || age > 100) return alert('请输入合法的年龄,0-100岁');
//验证通过,提交数据,
//提交数据之前禁用按钮
var that = this;
$(that).prop('disabled',true);
//提交数据
$.post(api, form.serialize() ,function(res){
//服务器返回结果处理,按钮取消禁用状态
$(that).prop('disabled',false);
//根据返回的错误code判断是否处理成功,如果code==0,错误代码等于0表示没有错误
if(res.code == 0){
alert('表单提交成功');
$('#error').html( '' ).hide();
}else{
//表单提交失败,提示用户失败原因
$('#error').html( res.msg ).show();
}
})
});
```
## 附件
### 服务器提供的测试接口
可以使用接口,在后端未完成工作之前调试应用是否存在问题
1. http://wx.diggid.cn/api/ajax/success 此接口返回成功状态码 `code=0`
```javascript
{
"data": [],
"code": 0,
"msg": "你的操作成功接口"
}
```
2. http://wx.diggid.cn/api/ajax/error 此接口返回失败状态码 `code=-1`
```javascript
{
"data": [],
"code": -1,
"msg": "你的操作出现问题"
}
```
3. http://wx.diggid.cn/api/ajax/data 此接口将你提交的数据放在data中原样返回
```javascript
{
"data": [],
"code": 0,
"msg": "返回数据"
}
```
- 前端篇
- 常用知识点
- 表单处理
- 前后端分离
- 提供模板渲染工具
- 页面优化
- css3动画部分
- 前端工程与模块化框架
- 服务器XML标签用法
- 微信JSSDK
- 小技巧
- 纯CSS实现自适应正方形
- 通用媒体查询
- css 黑科技
- H5性能优化方案
- 10个最常见的 HTML5
- 常见坑
- 资源收集
- 前端组件化开发实践
- 应用秒开计划
- AJAX API部分
- 静态资源处理优化
- 后端篇
- 微信对接与管理
- 微信消息处理
- API插件开发
- Plugin开发
- 后端插件开发
- 组件开发
- XML标签开发
- RESTFUL设计
- Admin GUI
- 设计篇
- 设计规范
- 微信开发库v.js
- 使用方法
- 微信JSSDK集成
- 调试面板使用
- 插件-http功能
- 插件-layer弹出层
- 插件-music 音乐播放器
- 插件-store 本地存储
- 插件 emitter 事件管理器
- 插件-shake 摇动功能
- 插件-lazyload 延迟加载
- 插件-t 模板渲染
- 插件-ani 动画功能
- 插件-is 类型侦测器
- 插件-ease 缓动函数库
- 插件-os 设备检测
- 插件 $ 类Jquery插件
- 插件-md5 散列计算
- 插件-svg动画loading
- 后台页面成功GUI
- 列表渲染List
- 表单生成Config
- 树状列表Tree
- 排序操作Sort
- Js 风格指南
- Vuep
- 内置动画库
- 组件库
- 内置插件库
- PSD自动切图