表單基礎(chǔ)知識(shí)
在HTML中,表單是使用form元素來表示的倡蝙,JS中對應(yīng)的是HTMLFormElement類型。它同樣繼承自HTMLElement,還有一些自己的方法:
1.acceptCharset:服務(wù)器能處理的字符集
2.action:接受請求的URL
3.elements:表單中所有控件的集合(HTMLCollection)
4.enctype:請求的編碼類型
5.length:表單中所有控件的數(shù)量
6.method:要發(fā)送的HTTP請求類型缰趋,通常是get或post
7.name:表單的名稱
8.reset():將所有表單域重置為默認(rèn)值
9.submit():提交表單
10.target:用于發(fā)送請求和接收響應(yīng)的窗口名稱
通過document.forms可以取得頁面中所有的表單。在這個(gè)集合里铛只,可以通過數(shù)值索引或 name 值來取得特定的表單埠胖。
var firstForm = document.forms[0];
var myForm = document.forms["form2"];
- 提交表單
用戶單擊提交按鈕或圖像按鈕時(shí)就回提交表單。
//html
<input type="submit" value="Submit Form">
<button type="submit">Submit Form</button>
<input type="image" src="graphic.gif">
表單中存在上述任何一種按鈕時(shí)淳玩,在表單中元素具有焦點(diǎn)的情況下直撤,按回車就可以提交該表單。
submit同樣是一種事件類型蜕着,通過設(shè)置事件處理函數(shù)可以改變其行為谋竖,比如取消掉红柱。
//js
var form = document.getElementById("myForm");
EventUtil.addHandler(form, "submit", function(event) {
//取得事件對象
event = EventUtil.getEvent(event);
//阻止默認(rèn)事件
EventUtil.preventDefault(event);
});
可以通過代碼來觸發(fā)submit操作,但是不會(huì)觸發(fā)submit事件蓖乘。
firstForm.submit();
- 重置表單
就是清空所有表單數(shù)據(jù)
<input type="reset" value="Reset Form">
<button type="reset">Reset Form</button>
這同樣會(huì)觸發(fā)一個(gè)reset事件
var form = document.getElementById("myForm");
EventUtil.addHandler(form, "reset", function(event) {
//取得事件對象
event = EventUtil.getEvent(event);
//阻止表單重置
EventUtil.preventDefault(event);
});
使用form.reset()方法重置表單時(shí)還是會(huì)觸發(fā)reset事件的锤悄。
- 表單字段
每個(gè)表單都有elements屬性,該屬性時(shí)表單中所有表單元素的集合嘉抒,是有序的零聚。通過位置和name都可以訪問。
alert(firstForm.elements[0].name);
alert(firstForm.elements["password"].name);
alert(firstForm.elements.length);
如果有相同name的元素些侍,那么就回返回一個(gè)NodeList
共有的表單字段屬性:
1.disabled
2.form:指向當(dāng)前字段所屬的表單的的指針隶症,只讀
3.name:當(dāng)前字段的名稱
4.readOnly:當(dāng)前字段是否只讀
5.tabIndex:當(dāng)前字段的切換序號(hào)
6.type:“checkbox”、“radio”
7.value:當(dāng)前字段將被提交給服務(wù)器的值岗宣,對于文件字段來說這個(gè)屬性是只讀的蚂会,包含文件在計(jì)算機(jī)中的路徑
JS可以動(dòng)態(tài)修改他們。
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不能聚焦到?jīng)]有被顯示出來的屬性胁住。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屬性來獲取他們的內(nèi)容刊咳。
特別提醒彪见,處理文本框的值的時(shí)候不要使用標(biāo)準(zhǔn)DOM修改特性或文本子節(jié)點(diǎn)的方法,使用value屬性芦缰,這樣才能保證value屬性的值(最終被提交到服務(wù)器的)和顯示的值是一致的企巢。
- 選擇文本
上述兩種文本框都支持select方法,這個(gè)方法用于選擇文本框中所有文本让蕾。
這個(gè)在焦點(diǎn)移到輸入框時(shí)自動(dòng)選擇其中的文本浪规。
var field = firstForm.elements[1];
EventUtil.addHandler(field, "focus", function(event){
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
target.select();
});
//選擇事件
//選擇文本框內(nèi)的文本或使用select()時(shí)會(huì)觸發(fā)select事件。
取得選擇的文本
HTML5中使用這兩個(gè)屬性selectionStart探孝、selectionEnd取得選擇的文本,這兩個(gè)表示所選擇文本的范圍(即是文本的開頭和結(jié)尾的偏移量)
IE8及以下不支持笋婿,使用替代方案,不管用戶在頁面上選擇了什么都會(huì)創(chuàng)建一個(gè)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()方法接收兩個(gè)參數(shù)要選擇的第一個(gè)字符的索引和最后一個(gè)字符的索引缸濒。然后把焦點(diǎn)移過來才能看到
//選擇前三個(gè)字符
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的默認(rèn)事件來阻止用戶輸入庇配。
像這樣就所有的字符都輸入不了啦,不過粘貼绍些,用輸入法之類的輸入并不通過keypress的就阻止不了了呦~捞慌,改成keydown事件用ctrl的粘貼也會(huì)被阻止:
EventUtil.addHandler(textbox, "keypress", function(event){
event = EventUtil.getEvent(event);
EventUtil.preventDefault(event);
});
針對特定的字符可以做特定的操作,比如只屏蔽數(shù)字鍵:
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個(gè)屬于剪貼板的事件:
1.beforecopy
2.copy
3.beforecut
4.cut
5.beforepaste
6.paste
beforecopy柬批、beforecut啸澡、beforepaste袖订,在IE中一直會(huì)在真正的復(fù)制粘貼前被觸發(fā),其他瀏覽器中貌似不大好用嗅虏。就用另外3個(gè)就足夠啦洛姑。
在這個(gè)事件中clipboardData使用來訪問剪貼板中的數(shù)據(jù),IE中是window.clipboardData皮服,其他是event.clipboardData需要做下兼容楞艾。它有3個(gè)方法:getData()、setData()冰更、clearData()产徊,他們接收的參數(shù)是數(shù)據(jù)類型,瀏覽器之間也有差異需要兼容~:
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);
}
}
剪貼板事件時(shí)調(diào)用一下蜀细,就可以控制復(fù)制粘貼的內(nèi)容啦,知乎就是這么干的戈盈。
EventUtil.addHandler(text, "paste", function(event){
event = EventUtil.getEvent(event);
var text = EventUtil.getClipboardText(event);
if (!/^\d*$/.test(text)){
EventUtil.preventDefault(event);
}
});
- 自動(dòng)切換焦點(diǎn)
自動(dòng)切換焦點(diǎn)小功能
(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約束驗(yàn)證API
脫離JS即便JS不能加載奠衔,用HTML5的特性也能完成部分驗(yàn)證。
必填字段
<input type="text" name="username" required>
其他輸入類型
有的輸入字段自帶驗(yàn)證:
<input type="email" name ="email">
<input type="url" name="homepage">
除了email塘娶,url還有"number"归斤,"range","datetime"刁岸,"datetime-local"脏里,"date","month"虹曙,"week"迫横,"time"不過支持并不好。
數(shù)值范圍
<input type="number" min="0" max="100" step="5" name="count">
//想用戶輸入0到100的值酝碳,而且必須是5的倍數(shù)
input.stepUp(); //加 1
input.stepUp(5); //加 5
input.stepDown();
input.stepDown(10);//減10
輸入模式
這個(gè)屬性是一個(gè)正則表達(dá)式
<input type="text" pattern="\d+" name="count">
var pattern = document.forms[0].elements["count"].pattern;
- 檢測有效性
checkValidity()矾踱,這個(gè)方法可以用在整個(gè)表單,也可以用在某個(gè)字段疏哗。有效返回true呛讲。
if(document.forms[0].checkValidity()){
//表單有效
} else{
//表單無效
}
validity,這個(gè)屬性是個(gè)對象返奉,會(huì)更加詳細(xì)的告訴你為什么字段有效或無效贝搁。這個(gè)對象中包含一系列屬性,都是布爾值:
1.customError:如果設(shè)置了setCustomValidity()則為true芽偏,否則為false
2.patternMismatch:如果設(shè)置了和指定的pattern不匹配雷逆,返回true
3.rangeOverflow:如果值比max大,返回true
4.rangeUnderflow:如果值比min小哮针,返回true
5.stepMisMatch:如果min和max之間的步長值不符合step关面,返回true
6.tooLong:如果值的長度超過了maxlength屬性指定的長度坦袍,放回true。有的瀏覽器(如Firefox4)等太,會(huì)自動(dòng)約束字符數(shù)量捂齐。
7.typeMismatch:如果值不是“url”或者“mail”要求的格式,返回true
8.valid:如果這里的其他屬性都是false缩抡,返回true奠宜。checkValidity()也要求有相同的值
9.valueMissing:如同標(biāo)注為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.");
}
}
- 禁用驗(yàn)證
<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元素創(chuàng)建压真。select在JS中為HTMLSelectElement。有下列屬性和方法:
選擇框是通過<select>和<option>元素創(chuàng)建的蘑险。為了方便與這個(gè)控件交互滴肿,除了所有表單字段公有的屬性和方法外,HTMLSelectElement類型還提供了下列屬性和方法佃迄。
1.add(newOption, relOption):向控件中插入新<option>元素泼差,其位置在相關(guān)項(xiàng)之前。
2.multiple:布爾值呵俏,表示是否允許多項(xiàng)選擇堆缘,等價(jià)于 HTML 中的multiple特性。
3.options:控件中所有<option>元素的HTMLCollection普碎。
4.remove(index): 移除給定位置的選項(xiàng)吼肥。
5.selectedIndex:基于 0 的選中項(xiàng)的索引,如果沒有選中項(xiàng)麻车,則值為 -1缀皱。對于支持多選的控件,只保存選中項(xiàng)中第一項(xiàng)的索引绪氛。
6.size:選擇框中可見的行數(shù)唆鸡;等價(jià)于 HTML 的size特性。
選擇框的type屬性不是"select-one"枣察,就是"select-multiple"争占,這取決于 HTML 代碼中有沒有multiple特性。選擇框的value屬性由當(dāng)前選中項(xiàng)決定序目。
在 DOM 中臂痕,每個(gè)<option>元素都有一個(gè)HTMLOptionElement對象表示。為便于訪問數(shù)據(jù)猿涨,HTMLOptionElement對象添加了下列屬性:
1.index:當(dāng)前選項(xiàng)在options集合中的索引握童。
2.label:當(dāng)前選項(xiàng)的標(biāo)簽;等價(jià)于 HTML 中的label特性叛赚。
3.selected:布爾值澡绩,表示當(dāng)前選項(xiàng)是否被選中稽揭。將這個(gè)屬性設(shè)置為true可以選中當(dāng)前選項(xiàng)。
4.text:選項(xiàng)的文本肥卡。
5.value:選項(xiàng)的值(等價(jià)于 HTML 中的value特性)溪掀。
- 選擇選項(xiàng)
1.對于只允許選擇一項(xiàng)的選擇框,訪問選中項(xiàng)的最簡單方式步鉴,就是使用選擇框的selectedIndex屬性揪胃。
2.多選選擇框,設(shè)置selectedIndex屬性會(huì)導(dǎo)致取消以前的所有選項(xiàng)并選擇指定的那一項(xiàng)氛琢,而讀取selectedIndex則會(huì)返回選中項(xiàng)中第一項(xiàng)的索引值喊递。
另一種選擇選項(xiàng)的方式,就是取得對某一項(xiàng)的引用阳似,然后將其selected屬性設(shè)置為true骚勘。
3.要取得所有選中的項(xiàng),可以循環(huán)遍歷選項(xiàng)集合撮奏,然后測試每個(gè)選項(xiàng)的selected屬性调鲸。
注:多選框可以通過設(shè)置selected屬性選中任意多個(gè)項(xiàng)。在單選框中挽荡,修改某個(gè)選項(xiàng)的selected屬性則會(huì)取消對其他選項(xiàng)的選擇。需要注意的是即供,將selected屬性設(shè)置為false對單選框沒有影響定拟。
//只允許選擇一項(xiàng)
var selectedOption = selectbox.options[selectbox.selectedIndex];
//多選擇框的時(shí)候使用selected屬性
selectbox.options[0].selected = true;
//取得所有選中的項(xiàng)
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;
}
- 添加選項(xiàng)
1.使用 DOM 方法。(最佳方案)
2.使用Option構(gòu)造函數(shù)逗嫡。
3.使用選擇框的add()方法青自。兼容 DOM 的瀏覽器要求必須指定第二個(gè)參數(shù)。
//第一種方法
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);
如果你想將新選項(xiàng)添加到其他位置(不是最后一個(gè))驱证,就應(yīng)該使用標(biāo)準(zhǔn)的 DOM 技術(shù)和insertBefore()方法延窜。
- 移除選項(xiàng)
1.首先,可以使用 DOM 的removeChild()方法抹锄,為其傳入要移除的選項(xiàng).
2.其次逆瑞,可以使用選擇框的remove()方法。這個(gè)方法可以接受一個(gè)參數(shù)伙单,即要移除選項(xiàng)的索引获高,
3.最后一種方式,就是將相應(yīng)選項(xiàng)設(shè)置為null吻育。這種方式也是 DOM 出現(xiàn)之前瀏覽器的遺留機(jī)制念秧。
4.要清除選擇框中所有的項(xiàng),需要迭代所有選項(xiàng)并逐個(gè)移除它們布疼。如下所示:
//第一種方法
selectbox.removeChild(selectbox.options[0]);
//第二種方法
selectbox.remove(0);
//第三種方法
selectbox.options[0] = null;
//清除所有的項(xiàng)
function clearSelectbox(selectbox) {
for (var i=0, len=selectbox.options.length; i < len; i++) {
selectbox.remove(i?0);
}
}
- 移動(dòng)和重排選項(xiàng)
1.移動(dòng)使用 DOM 的appendChild()方法摊趾。
2.重排最合適的 DOM 的方法就是insertBefore()币狠。
表單序列化
隨著 Ajax 的出現(xiàn),表單序列化已經(jīng)成為一種常見需求砾层′雒啵可以利用表單字段的type屬性,連同name和value屬性一起實(shí)現(xiàn)對表單的序列化梢为。在編寫代碼之前渐行,必須先搞清楚在表單提交期間,瀏覽器是怎樣將數(shù)據(jù)發(fā)送給服務(wù)器的铸董。
- 對表單字段的名稱和值進(jìn)行 URL 編碼祟印,使用和號(hào)(&)分隔。
- 不發(fā)送禁用的表單字段粟害。
- 只發(fā)送勾選的復(fù)選框和單選按鈕蕴忆。
- 不發(fā)送 type 為“reset”和“button”的按鈕。
- 多選選擇框中的每個(gè)選中的值單獨(dú)一個(gè)條目悲幅。
- 在單擊提交按鈕提交表單的情況下套鹅,也會(huì)發(fā)送提交按鈕;否則汰具,不發(fā)送提交按鈕卓鹿。也包括type為“image”的<input>元素。
- <select>元素的值留荔,就是選中的<option>元素的value特性的值吟孙。如果<option>元素沒有value特性,則是<option>元素的文本值聚蝶。
以下就是實(shí)現(xiàn)表單序列化的代碼杰妓。
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": //復(fù)選框
if(!field.checked) {
break;
}
/* 執(zhí)行默認(rèn)操作 */
default: //不包含沒有名字的表單字段
if (field.name.length) {
parts.push(encodeURIComponent(field.name) + "=" + encodeURIComponent(field.value));
}
}
}
return parts.join("&");
}