# 表單處理
[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自動切圖