表單基礎知識
在HTML中,表單是使用form元素來表示的,JS中對應的是HTMLFormElement類型。它同樣繼承自HTMLElement,還有一些自己的方法:
1.acceptCharset:服務器能處理的字符集
2.action:接受請求的URL
3.elements:表單中所有控件的集合(HTMLCollection)
4.enctype:請求的編碼類型
5.length:表單中所有控件的數量
6.method:要發送的HTTP請求類型,通常是get或post
7.name:表單的名稱
8.reset():將所有表單域重置為默認值
9.submit():提交表單
10.target:用于發送請求和接收響應的窗口名稱
通過document.forms可以取得頁面中所有的表單。在這個集合里,可以通過數值索引或 name 值來取得特定的表單。
var firstForm = document.forms[0];
var myForm = document.forms["form2"];
- 提交表單
用戶單擊提交按鈕或圖像按鈕時就回提交表單。
//html
<input type="submit" value="Submit Form">
<button type="submit">Submit Form</button>
<input type="image" src="graphic.gif">
表單中存在上述任何一種按鈕時,在表單中元素具有焦點的情況下,按回車就可以提交該表單。
submit同樣是一種事件類型,通過設置事件處理函數可以改變其行為,比如取消掉。
//js
var form = document.getElementById("myForm");
EventUtil.addHandler(form, "submit", function(event) {
//取得事件對象
event = EventUtil.getEvent(event);
//阻止默認事件
EventUtil.preventDefault(event);
});
可以通過代碼來觸發submit操作,但是不會觸發submit事件。
firstForm.submit();
- 重置表單
就是清空所有表單數據
<input type="reset" value="Reset Form">
<button type="reset">Reset Form</button>
這同樣會觸發一個reset事件
var form = document.getElementById("myForm");
EventUtil.addHandler(form, "reset", function(event) {
//取得事件對象
event = EventUtil.getEvent(event);
//阻止表單重置
EventUtil.preventDefault(event);
});
使用form.reset()方法重置表單時還是會觸發reset事件的。
- 表單字段
每個表單都有elements屬性,該屬性時表單中所有表單元素的集合,是有序的。通過位置和name都可以訪問。
alert(firstForm.elements[0].name);
alert(firstForm.elements["password"].name);
alert(firstForm.elements.length);
如果有相同name的元素,那么就回返回一個NodeList
共有的表單字段屬性:
1.disabled
2.form:指向當前字段所屬的表單的的指針,只讀
3.name:當前字段的名稱
4.readOnly:當前字段是否只讀
5.tabIndex:當前字段的切換序號
6.type:“checkbox”、“radio”
7.value:當前字段將被提交給服務器的值,對于文件字段來說這個屬性是只讀的,包含文件在計算機中的路徑
JS可以動態修改他們。
var field = firstForm.elements[0];
field.value = "Another value";
alert(field.form === firstForm);
field.focus();
field.disabled = true;
field.type = "checkbox";
避免多次提交表單就可以在submit事件中禁用提交按鈕。
共有的表單字段方法:
1.focus()
2.blur()
注:focus不能聚焦到沒有被顯示出來的屬性。HTML5有autofocus屬性。
共有的表單字段事件
1.blur
2.change
3.focus
文本框腳本
文本框有兩種input和textarea
<input type="text" size="25" maxlength="50" value="initial value">
<textarea rows="25" cols="5">initial value</textarea>
在JS中可以使用value屬性來獲取他們的內容。
特別提醒,處理文本框的值的時候不要使用標準DOM修改特性或文本子節點的方法,使用value屬性,這樣才能保證value屬性的值(最終被提交到服務器的)和顯示的值是一致的。
- 選擇文本
上述兩種文本框都支持select方法,這個方法用于選擇文本框中所有文本。
這個在焦點移到輸入框時自動選擇其中的文本。
var field = firstForm.elements[1];
EventUtil.addHandler(field, "focus", function(event){
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
target.select();
});
//選擇事件
//選擇文本框內的文本或使用select()時會觸發select事件。
取得選擇的文本
HTML5中使用這兩個屬性selectionStart、selectionEnd取得選擇的文本,這兩個表示所選擇文本的范圍(即是文本的開頭和結尾的偏移量)
IE8及以下不支持,使用替代方案,不管用戶在頁面上選擇了什么都會創建一個document.selection對象
兼容代碼如下:
EventUtil.addHandler(field, "select", function(event){
console.log(getSelectedText(field));
});
function getSelectedText(textbox) {
if (typeof textbox.selectionStart == "number") {
return textbox.value.substring(textbox.selectionStart, textbox.selectionEnd);
} else if (document.selection) {
return document.selection.createRange().text;
}
}
選擇部分文本
剛才的select方法只能選擇全部文本,setSelectionRange()方法接收兩個參數要選擇的第一個字符的索引和最后一個字符的索引。然后把焦點移過來才能看到
//選擇前三個字符
textbox.setSelectionRange(0, 3);
text.focus();
IE8不支持,又得用范圍那一套。
function selectText(textbox, startIndex, stopIndex){
if (textbox.setSelectionRange){
textbox.setSelectionRange(startIndex, stopIndex);
} else if (textbox.createTextRange){
var range = textbox.createTextRange();
range.collapse(true);
range.moveStart("character", startIndex);
range.moveEnd("character", stopIndex - startIndex);
range.select();
}
textbox.focus();
}
selectText(text,0,3);
- 過濾輸入
屏蔽字符
通過阻止keypress的默認事件來阻止用戶輸入。
像這樣就所有的字符都輸入不了啦,不過粘貼,用輸入法之類的輸入并不通過keypress的就阻止不了了呦~,改成keydown事件用ctrl的粘貼也會被阻止:
EventUtil.addHandler(textbox, "keypress", function(event){
event = EventUtil.getEvent(event);
EventUtil.preventDefault(event);
});
針對特定的字符可以做特定的操作,比如只屏蔽數字鍵:
EventUtil.addHandler(text, "keypress", function(event){
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
var charCode = EventUtil.getCharCode(event);
if (!/\d/.test(String.fromCharCode(charCode)) && charCode > 9){
EventUtil.preventDefault(event);
}
});
操作剪貼板
有6個屬于剪貼板的事件:
1.beforecopy
2.copy
3.beforecut
4.cut
5.beforepaste
6.paste
beforecopy、beforecut、beforepaste,在IE中一直會在真正的復制粘貼前被觸發,其他瀏覽器中貌似不大好用。就用另外3個就足夠啦。
在這個事件中clipboardData使用來訪問剪貼板中的數據,IE中是window.clipboardData,其他是event.clipboardData需要做下兼容。它有3個方法:getData()、setData()、clearData(),他們接收的參數是數據類型,瀏覽器之間也有差異需要兼容~:
getClipboardText: function(event){
var clipboardData = (event.clipboardData || window.clipboardData);
return clipboardData.getData("text");
},
setClipboardText: function(event, value){
if (event.clipboardData){
return event.clipboardData.setData("text/plain", value);
} else if (window.clipboardData){
return window.clipboardData.setData("text", value);
}
}
剪貼板事件時調用一下,就可以控制復制粘貼的內容啦,知乎就是這么干的。
EventUtil.addHandler(text, "paste", function(event){
event = EventUtil.getEvent(event);
var text = EventUtil.getClipboardText(event);
if (!/^\d*$/.test(text)){
EventUtil.preventDefault(event);
}
});
- 自動切換焦點
自動切換焦點小功能
(function(){
function tabForward(event){
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
if (target.value.length == target.maxLength){
var form = target.form;
for (var i=0, len=form.elements.length; i < len; i++) {
if (form.elements[i] == target) {
if (form.elements[i+1]){
form.elements[i+1].focus();
}
return;
}
}
}
}
var textbox1 = document.getElementById("txtTel1");
var textbox2 = document.getElementById("txtTel2");
var textbox3 = document.getElementById("txtTel3");
EventUtil.addHandler(textbox1, "keyup", tabForward);
EventUtil.addHandler(textbox2, "keyup", tabForward);
EventUtil.addHandler(textbox3, "keyup", tabForward);
})();
- HTML5約束驗證API
脫離JS即便JS不能加載,用HTML5的特性也能完成部分驗證。
必填字段
<input type="text" name="username" required>
其他輸入類型
有的輸入字段自帶驗證:
<input type="email" name ="email">
<input type="url" name="homepage">
除了email,url還有"number","range","datetime","datetime-local","date","month","week","time"不過支持并不好。
數值范圍
<input type="number" min="0" max="100" step="5" name="count">
//想用戶輸入0到100的值,而且必須是5的倍數
input.stepUp(); //加 1
input.stepUp(5); //加 5
input.stepDown();
input.stepDown(10);//減10
輸入模式
這個屬性是一個正則表達式
<input type="text" pattern="\d+" name="count">
var pattern = document.forms[0].elements["count"].pattern;
- 檢測有效性
checkValidity(),這個方法可以用在整個表單,也可以用在某個字段。有效返回true。
if(document.forms[0].checkValidity()){
//表單有效
} else{
//表單無效
}
validity,這個屬性是個對象,會更加詳細的告訴你為什么字段有效或無效。這個對象中包含一系列屬性,都是布爾值:
1.customError:如果設置了setCustomValidity()則為true,否則為false
2.patternMismatch:如果設置了和指定的pattern不匹配,返回true
3.rangeOverflow:如果值比max大,返回true
4.rangeUnderflow:如果值比min小,返回true
5.stepMisMatch:如果min和max之間的步長值不符合step,返回true
6.tooLong:如果值的長度超過了maxlength屬性指定的長度,放回true。有的瀏覽器(如Firefox4),會自動約束字符數量。
7.typeMismatch:如果值不是“url”或者“mail”要求的格式,返回true
8.valid:如果這里的其他屬性都是false,返回true。checkValidity()也要求有相同的值
9.valueMissing:如同標注為required的字段沒有值,返回true。
if (input.validity && !input.validity.valid){
if (input.validity.valueMissing){
alert("Please specify a value.")
} else if (input.validity.typeMismatch){
alert("Please enter an email address.");
} else {
alert("Value is invalid.");
}
}
- 禁用驗證
<form method="post" action="signup.php" novalidate>
<!--表-->
</form>
document.forms[0].noValidate = true; //
<input type="submit" formnovalidate name="btnNoValidate" value="Non-validating Submit">
document.forms[0].elements["btnNoValidate"].formNoValidate = true;
選擇框腳本
選擇框通過select和option元素創建。select在JS中為HTMLSelectElement。有下列屬性和方法:
選擇框是通過<select>和<option>元素創建的。為了方便與這個控件交互,除了所有表單字段公有的屬性和方法外,HTMLSelectElement類型還提供了下列屬性和方法。
1.add(newOption, relOption):向控件中插入新<option>元素,其位置在相關項之前。
2.multiple:布爾值,表示是否允許多項選擇,等價于 HTML 中的multiple特性。
3.options:控件中所有<option>元素的HTMLCollection。
4.remove(index): 移除給定位置的選項。
5.selectedIndex:基于 0 的選中項的索引,如果沒有選中項,則值為 -1。對于支持多選的控件,只保存選中項中第一項的索引。
6.size:選擇框中可見的行數;等價于 HTML 的size特性。
選擇框的type屬性不是"select-one",就是"select-multiple",這取決于 HTML 代碼中有沒有multiple特性。選擇框的value屬性由當前選中項決定。
在 DOM 中,每個<option>元素都有一個HTMLOptionElement對象表示。為便于訪問數據,HTMLOptionElement對象添加了下列屬性:
1.index:當前選項在options集合中的索引。
2.label:當前選項的標簽;等價于 HTML 中的label特性。
3.selected:布爾值,表示當前選項是否被選中。將這個屬性設置為true可以選中當前選項。
4.text:選項的文本。
5.value:選項的值(等價于 HTML 中的value特性)。
- 選擇選項
1.對于只允許選擇一項的選擇框,訪問選中項的最簡單方式,就是使用選擇框的selectedIndex屬性。
2.多選選擇框,設置selectedIndex屬性會導致取消以前的所有選項并選擇指定的那一項,而讀取selectedIndex則會返回選中項中第一項的索引值。
另一種選擇選項的方式,就是取得對某一項的引用,然后將其selected屬性設置為true。
3.要取得所有選中的項,可以循環遍歷選項集合,然后測試每個選項的selected屬性。
注:多選框可以通過設置selected屬性選中任意多個項。在單選框中,修改某個選項的selected屬性則會取消對其他選項的選擇。需要注意的是,將selected屬性設置為false對單選框沒有影響。
//只允許選擇一項
var selectedOption = selectbox.options[selectbox.selectedIndex];
//多選擇框的時候使用selected屬性
selectbox.options[0].selected = true;
//取得所有選中的項
function getSelectedOption(selectbox) {
var result = new Array();
var option = null;
for (var i=0,len=selectbox.options.length; i < len; i++) {
option = selectbox.options[i];
if (option.selected) {
result.push(option);
}
}
return result;
}
- 添加選項
1.使用 DOM 方法。(最佳方案)
2.使用Option構造函數。
3.使用選擇框的add()方法。兼容 DOM 的瀏覽器要求必須指定第二個參數。
//第一種方法
var newOption = document.createElement("option");
newOption.appendChild(document.createTextNode("Option text"));
newOption.setAttribute("value","Option value");
selectbox.appendChild(newOption);
//第二種方法
var newOption = new Option("Option text", "Option value");
selectbox.appendChild(newOption);
//第三種方法
var newOption = new Option("Option text", "Option value");
selectbox.add(newOption, undefined);
如果你想將新選項添加到其他位置(不是最后一個),就應該使用標準的 DOM 技術和insertBefore()方法。
- 移除選項
1.首先,可以使用 DOM 的removeChild()方法,為其傳入要移除的選項.
2.其次,可以使用選擇框的remove()方法。這個方法可以接受一個參數,即要移除選項的索引,
3.最后一種方式,就是將相應選項設置為null。這種方式也是 DOM 出現之前瀏覽器的遺留機制。
4.要清除選擇框中所有的項,需要迭代所有選項并逐個移除它們。如下所示:
//第一種方法
selectbox.removeChild(selectbox.options[0]);
//第二種方法
selectbox.remove(0);
//第三種方法
selectbox.options[0] = null;
//清除所有的項
function clearSelectbox(selectbox) {
for (var i=0, len=selectbox.options.length; i < len; i++) {
selectbox.remove(i?0);
}
}
- 移動和重排選項
1.移動使用 DOM 的appendChild()方法。
2.重排最合適的 DOM 的方法就是insertBefore()。
表單序列化
隨著 Ajax 的出現,表單序列化已經成為一種常見需求??梢岳帽韱巫侄蔚膖ype屬性,連同name和value屬性一起實現對表單的序列化。在編寫代碼之前,必須先搞清楚在表單提交期間,瀏覽器是怎樣將數據發送給服務器的。
- 對表單字段的名稱和值進行 URL 編碼,使用和號(&)分隔。
- 不發送禁用的表單字段。
- 只發送勾選的復選框和單選按鈕。
- 不發送 type 為“reset”和“button”的按鈕。
- 多選選擇框中的每個選中的值單獨一個條目。
- 在單擊提交按鈕提交表單的情況下,也會發送提交按鈕;否則,不發送提交按鈕。也包括type為“image”的<input>元素。
- <select>元素的值,就是選中的<option>元素的value特性的值。如果<option>元素沒有value特性,則是<option>元素的文本值。
以下就是實現表單序列化的代碼。
function serialize(form) {
var parts = [],
field = null,
i,
len,
j,
optLen,
option,
optValue;
for (i=0, len=form.elements.length; i < len; i++) {
field = form.elements[i];
switch(field.type) {
case "select-one":
case "select-multiple":
if (field.name.length) {
for (j=0,optLen = field.options.length; j < optLen; j++) {
option = field.options[j];
if (option.selected) {
optValue = "";
if (option.hasAttribute) {
optValue = option.hasAttribute("value") ? option.value : option.text;
} else {
optValue = option.attributes("value").specified ? option.value : option.text;
}
parts.push(encodeURIComponent(field.name) + "=" + encodeURIComponent(optValue));
}
}
}
break;
case undefined: //字段集
case "file": //文件輸入
case "submit": //提交按鈕
case "reset": //重置按鈕
case "button": //自定義按鈕
break;
case "radio": //單選按鈕
case "checkbox": //復選框
if(!field.checked) {
break;
}
/* 執行默認操作 */
default: //不包含沒有名字的表單字段
if (field.name.length) {
parts.push(encodeURIComponent(field.name) + "=" + encodeURIComponent(field.value));
}
}
}
return parts.join("&");
}