上門一對一計算機家教
當前位置: 首頁 > Web前端家教 >

Javascript自學筆記第14節 表單處理[堅持]

點擊: 時間:2016-10-20 來源:北京家教網
為了分擔服務器處理表單的壓力,JavaScript提供了一些解決方案,從而大大打破了處處依賴服務器的局面。 一. 表單介紹 在HTML中,表單是由form元素來表示的,而在JavaScript中,表單對應的則是HTMLFormElement類型。HTMLFormElement繼承
為了分擔服務器處理表單的壓力,JavaScript提供了一些解決方案,從而大大打破了處處依賴服務器的局面。
 
一.表單介紹
在HTML中,表單是由<form>元素來表示的,而在JavaScript中,表單對應的則是HTMLFormElement類型。HTMLFormElement繼承了HTMLElement,因此它擁有HTML元素具有的默認屬性,并且還獨有自己的屬性和方法:
 
HTMLFormElement屬性和方法
屬性或方法 說明
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事件的默認行為就是攜帶數據跳轉到指定頁面。
       addEvent(fm, 'submit', function (evt) {
              preDef(evt);
       });
 
我們可以可以使用submit()方法來自定義觸發submit事件,也就是說,并不一定非要點擊submit按鈕才能提交。
if (e.ctrlKey && e.keyCode == 13) fm.submit(); //判斷按住了ctrl和enter鍵觸發
 
PS:在表單中盡量避免使用name="submit"或id="submit"等命名,這會和submit()方法發生沖突導致無法提交。
 
提交數據最大的問題就是重復提交表單。因為各種原因,當一條數據提交到服務器的時候會出現延遲等長時間沒反映,導致用戶不停的點擊提交,從而使得重復提交了很多相同的請求,或造成錯誤、或寫入數據庫多條相同信息。
       addEvent(fm, 'submit', function (evt) {               //模擬延遲
              preDef(evt);
              setTimeout(function () {
                     fm.submit();
              }, 3000);
       });
 
有兩種方法可以解決這種問題:第一種就是提交之后,立刻禁用點擊按鈕;第二種就是提交之后取消后續的表單提交操作。
document.getElementById('sub').disabled = true; //將按鈕禁用
 
var flag = false                                                 //設置一個監聽變量
if (flag == true) return                                      //如果存在返回退出事件
flag = true;                                                      //否則確定是第一次,設置為true
 
PS:在某些瀏覽器,F5只能起到緩存刷新的效果,有可能獲取不到真正的源頭更新的數據。那么使用ctrl+F5就可以把源頭給刷出來。
 
重置表單
用戶點擊重置按鈕時,表單會被初始化。雖然這個按鈕還得以保留,但目前的Web已經很少去使用了。因為用戶已經填寫好各種數據,不小心點了重置就會全部清空,用戶體驗極差。
有兩種方法調用reset事件,第一個就是直接type="reset"即可;第二個就是使用fm.reset()方法調用即可。
<input type="reset" value="重置" />                  //不需要JS代碼即可實現
       addEvent(document,'click', function () {            
              fm.reset();                                                //使用JS方法實現重置
       });                
addEvent(fm,'reset', function () {                       //獲取重置按鈕
//
});                                                   
 
表單字段
如果想訪問表單元素,可以使用之前章節講到的DOM方法訪問。但使用原生的DOM訪問雖然比較通用,但不是很便利。表單處理中,我們建議使用HTML DOM,它有自己的elements屬性,該屬性是表單中所有元素的集合。
fm.elements[0];                                                //獲取第一個表單字段元素
fm.elements['user'];                                           //獲取name是user的表單字段元素
fm.elements.length;                                                 //獲取所有表單字段的數量
 
如果多個表單字段都使用同一個name,那么就會返回該name的NodeList表單列表。
fm.elements['sex'];                                            //獲取相同name表單字段列表         
 
PS:我們是通過fm.elements[0]來獲取第一個表單字段的,但也可以使用fm[0]直接訪問第一個字段。因為fm[0]訪問方式是為了向下兼容的,所以,我們建議大家使用elements屬性來獲取。
 
共有的表單字段屬性
除了<fieldset>元素之外,所有表單字段都擁有相同的一組屬性。由于<input>類型可以表示多種表單字段,因此有些屬性只適用于某些字段。以下羅列出共有的屬性:
 
屬性或方法 說明
disabled 布爾值,表示當前字段是否被禁用
form 指向當前字段所屬表單的指針,只讀
name 當前字段的名稱
readOnly 布爾值,表示當前字段是否只讀
tabIndex 表示當前字段的切換
type 當前字段的類型
value 當前字段的值
 
 
這些屬性其實就是HTML表單里的屬性,在XHTML課程中已經詳細講解過,這里不一個個贅述,重點看幾個最常用的。
fm.elements[0].value;                                       //獲取和設置value
fm.elements[0].form == fm;                              //查看當前字段所屬表單
fm.elements[0].disabled = true;                          //禁用當前字段
fm.elements[0].type = 'checkbox';                      //修改字段類型,極不推薦
 
除了<fieldset>字段之外,所有表單字段都有type屬性。對于<input>元素,這個值等于HTML屬性的type值。對于非<input>元素,這個type的屬性值如下:
元素說明 HTML標簽 type屬性的值
單選列表 <select>...</select> select-one
多選列表 <select multiple>...</select> select-multiple
自定義按鈕 <button>...</button> button
自定義非提交按鈕 <button type="button">...</button> button
自定義重置按鈕 <button type="reset">...</button> reset
自定義提交按鈕 <button type="submit">...</button> submit
 
 
PS:<input>和<button>元素的type屬性是可以動態修改的,而<select>元素的type屬性則是只讀的。(在不必要的情況下,建議不修改type)。
 
共有的表單字段方法
每個表單字段都有兩個方法:foucs()和blur()。
方法 說明
focus() 將焦點定位到表單字段里
blur() 從元素中將焦點移走
 
 
       fm.elements[0].focus();                                     //將焦點移入
       fm.elements[0].blur();                                      //將焦點移出
 
共有的表單字段事件
表單共有的字段事件有以下三種:
事件名 說明
blur 當字段失去焦點時觸發
change 對于<input>和<textarea>元素,在改變value并失去焦點時觸發;對于<select>元素,在改變選項時觸發
focus 當前字段獲取焦點時觸發
 
 
       addEvent(textField, 'focus', function () {             //緩存blur和change再測試一下
              alert('Lee');
       });
 
PS:關于blur和change事件的關系,并沒有嚴格的規定。在某些瀏覽器中,blur事件會先于change事件發生;而在其他瀏覽器中,則恰好相反。
 
二.文本框腳本
在HTML中,有兩種方式來表現文本框:一種是單行文本框<input type="text">,一種是多行文本框<textarea>。雖然<input>在字面上有value值,而<textarea>卻沒有,但通過都可以通過value獲取他們的值。
       var textField = fm.elements[0];
       var areaField = fm.elements[1];
       alert(textField.value + ',' + areaField.value);        //得到value值
 
PS:使用表單的value是最推薦使用的,它是HTML DOM中的屬性,不建議使用標準DOM的方法。也就是說不要使用getAttribute()獲取value值。原因很簡單,對value屬性的修改,不一定會反映在DOM中。
 
除了value值,還有一個屬性對應的是defaultValue,可以得到原本的value值,不會因為值的改變而變化。
alert(textField.defaultValue);                             //得到最初的value值
 
選擇文本
使用select()方法,可以將文本框里的文本選中,并且將焦點設置到文本框中。
textField.select();                                             //選中文本框中的文本
 
選擇部分文本
在使用文本框內容的時候,我們有時要直接選定部分文本,這個行為還沒有標準。Firefox的解決方案是:setSelectionRange()方法。這個方法接受兩個參數:索引和長度。
textField.setSelectionRange(0,1);                                     //選擇第一個字符
textField.focus();                                                            //焦點移入
 
       textField.setSelectionRange(0, textField.value.length);              //選擇全部
       textField.focus();                                                            //焦點移入    
 
除了IE,其他瀏覽器都支持這種寫法(IE9+支持),那么IE想要選擇部分文本,可以使用IE的范圍操作。
       var range = textField.createTextRange();             //創建一個文本范圍對象
       range.collapse(true);                                         //將指針移到起點
       range.moveStart('character', 0);                          //移動起點,character表示逐字移動
       range.moveEnd('character', 1);                           //移動終點,同上
       range.select();                                                  //焦點選定
 
PS:關于IE范圍的詳細講解,我們將在今后的課程中繼續討論。并且W3C也有自己的范圍。
 
//選擇部分文本實現跨瀏覽器兼容
function selectText(text, start, stop) {
       if (text.setSelectionRange) {
              text.setSelectionRange(start, stop);
              text.focus();
       } else if (text.createTextRange) {
              var range = text.createTextRange();
              range.collapse(true);
              range.moveStart('character', start);
              range.moveEnd('character', stop - start);              //IE用終點減去起點得到字符數
              range.select();
       }
}
 
使用select事件,可以選中文本框文本后觸發。
       addEvent(textField, 'select', function () {
              alert(this.value);                                        //IE事件需要傳遞this才可以這么寫
       });
 
取得選擇的文本
如果我們想要取得選擇的那個文本,就必須使用一些手段。目前位置,沒有任何規范解決這個問題。Firefox為文本框提供了兩個屬性:selectionStart和selectionEnd。
       addEvent(textField, 'select', function () {
              alert(this.value.substring(this.selectionStart, this.selectionEnd));
       });
 
除了IE,其他瀏覽器均支持這兩個屬性(IE9+已支持)。IE不支持,而提供了另一個方案:selection對象,屬于document。這個對象保存著用戶在整個文檔范圍內選擇的文本信息。導致我們需要做瀏覽器兼容。
function getSelectText(text) {
       if (typeof text.selectionStart == 'number') {  //非IE
              return text.value.substring(text.selectionStart, text.selectionEnd);
       } else if (document.selection) {                   //IE
              return document.selection.createRange().text;      //獲取IE選擇的文本
       }
}
 
PS:有一個最大的問題,就是IE在觸發select事件的時候,在選擇一個字符后立即觸發,而其他瀏覽器是選擇想要的字符釋放鼠標鍵后才觸發。所以,如果使用alert()的話,導致跨瀏覽器的不兼容。我們沒有辦法讓瀏覽器行為保持統一,但可以通過不去使用alert()來解決。
       addEvent(textField, 'select', function () {
              //alert(getSelectText(this));                         //導致用戶行為結果不一致
              document.getElementById('box').innerHTML = getSelectText(this);
       });
 
過濾輸入
為了使文本框輸入指定的字符,我們必須對輸入進的字符進行驗證。有一種做法是判斷字符是否合法,這是提交后操作的。那么我們還可以在提交前限制某些字符,還過濾輸入。
       addEvent(areaField, 'keypress', function (evt) {
              var e = evt || window.event;
              var charCode = getCharCode(evt);               //得到字符編碼
              if (!/\d/.test(String.fromCharCode(charCode)) && charCode > 8) {  //條件阻止默認
                     preDef(evt);
              }
       });
 
PS:前半段條件判斷只有數字才可以輸入,導致常規按鍵,比如光標鍵、退格鍵、刪除鍵等無法使用。部分瀏覽器比如Firfox,需要解放這些鍵,而非字符觸發的編碼均為0;在Safari3之前的瀏覽器,也會被阻止,而它對應的字符編碼全部為8,所以最后就加上charCode > 8的判斷即可。
PS:當然,這種過濾還是比較脆落的,我們還希望能夠阻止裁剪、復制、粘貼和中文字符輸入操作才能真正屏蔽掉這些。
 
如果要阻止裁剪、復制和粘貼,那么我們可以在剪貼板相關的事件上進行處理,JavaScript提供了六組剪貼板相關的事件:
事件名 說明
copy 在發生復制操作時觸發
cut 在發生裁剪操作時觸發
paste 在發生粘貼操作時觸發
beforecopy 在發生復制操作前觸發
beforecut 在發生裁剪操作前觸發
beforepaste 在發生粘貼操作前觸發
 
 
由于剪貼板沒有標準,導致不同的瀏覽器有不同的解釋。Safari、Chrome和Firefox中,凡是before前綴的事件,都需要在特定條件下觸發。而IE則會在操作時之前觸發帶before前綴的事件。
如果我們想要禁用裁剪、復制、粘貼,那么只要阻止默認行為即可。
       addEvent(areaField, 'cut', function (evt) {           //阻止裁剪
              preDef(evt);
       });
       addEvent(areaField, 'copy', function (evt) {         //阻止復制
              preDef(evt);
       });
       addEvent(areaField, 'paste', function (evt) {        //阻止粘貼
              preDef(evt);
       });
 
當我們裁剪和復制的時候,我們可以訪問剪貼板里的內容,但問題是FireFox,Opera瀏覽器不支持訪問剪貼板。并且,不同的瀏覽器也有自己不同的理解。所以,這里我們就不在贅述。
 
最后一個問題影響到可能會影響輸入的因素就是:輸入法。我們知道,中文輸入法,它的原理是在輸入法面板上先存儲文本,按下回車就寫入英文文本,按下空格就寫入中文文本。
有一種解決方案是通過CSS來禁止調出輸入法:
style="ime-mode:disabled"                                //CSS直接編寫
areaField.style.imeMode = 'disabled';                  //或在JS里設置也可以
 
PS:但我們也發先,Chrome瀏覽器卻無法禁止輸入法調出。所以,為了解決谷歌瀏覽器的問題,最好還要使用正則驗證已輸入的文本。
       addEvent(areaField, 'keyup', function (evt) {              //keyup彈起的時候
              this.value = this.value.replace(/[^\d]/g, '');    //把非數字都替換成空
       });
 
自動切換焦點
為了增加表單字段的易用性,很多字段在滿足一定條件時(比如長度),就會自動切換到下一個字段上繼續填寫。
       <input type="text" name="user1" maxlength="1" />   //只能寫1個
       <input type="text" name="user2" maxlength="2" />   //只能寫2個
       <input type="text" name="user3" maxlength="3" />   //只能寫3個
 
       function tabForward (evt) {                                     
              var e = evt || window.event;
              var target = getTarget(evt);
              //判斷當前長度是否和指定長度一致
              if (target.value.length == target.maxLength) {    
//遍歷所有字段
                     for (var i =0; i < fm.elements.length; i ++) {
//找到當前字段
                            if (fm.elements[i] == target) {
//就把焦點移入下一個
                                   fm.elements[i + 1].focus();
//中途返回
                                   return;           
                            }
                     }
              }
       }
 
三.選擇框腳本
選擇框是通過<select>和<option>元素創建的,除了通用的一些屬性和方法外,HTMLSelectElement類型還提供了如下的屬性和方法:
HTMLSelectElement對象
屬性/方法 說明
add(new,rel) 插入新元素,并指定位置
multiple 布爾值,是否允許多項選擇
options <option>元素的HTMLColletion集合
remove(index) 移除給定位置的選項
selectedIndex 基于0的選中項的索引,如果沒有選中項,則值為-1
size 選擇框中可見的行數
 
 
在DOM中,每個<option>元素都有一個HTMLOptionElement對象,以便訪問數據,這個對象有如下一些屬性:
HTMLOptionElement對象
屬性 說明
index 當前選項在options集合中的索引
label 當前選項的標簽
selected 布爾值,表示當前選項是否被選中
text 選項的文本
value 選項的值
 
 
var city = fm.elements['city'];                             //HTMLSelectElement
alert(city.options);                                            //HTMLOptionsCollection
alert(city.options[0]);                                        //HTMLOptionElement
alert(city.type);                                                //select-one
 
PS:選擇框里的type屬性有可能是:select-one,也有可能是:select-multiple,這取決于HTML代碼中有沒有multiple屬性。
 
alert(city.options[0].firstChild.nodeValue);          //上海t,獲取text值,不推薦的做法
alert(city.options[0].getAttribute('value'));           //上海v,獲取value值,不推薦的做法
 
alert(city.options[0].text);                                  //上海t,獲取text值,推薦
alert(city.options[0].value);                               //上海v,獲取value值,推薦
 
PS:操作select時,最好使用HTML DOM,因為所有瀏覽器兼容的很好。而如果使用標準DOM,會因為不同的瀏覽器導致不同的結果。
PS:當選項沒有value值的時候,IE會返回空字符串,其他瀏覽器會返回text值。
 
選擇選項
對于只能選擇一項的選擇框,使用selectedIndex屬性最為簡單。
       addEvent(city, 'change', function () {
              alert(this.selectedIndex);                             //得到當前選項的索引,從0開始
alert(this.options[this.selectedIndex].text);   //得到當前選項的text值
alert(this.options[this.selectedIndex].value); //得到當前選項的value值
       });
PS:如果是多項選擇,他始終返回的是第一個項。
 
city.selectedIndex = 1;                                      //設置selectedIndex可以定位某個索引
 
通過option的屬性(布爾值),也可以設置某個索引,設置為true即可。
city.options[0].selected = true;                           //設置第一個索引
 
而selected和selectedIndex在用途上最大的區別是,selected是返回的布爾值,所以一般用于判斷上;而selectedIndex是數值,一般用于設置和獲取。
       addEvent(city, 'change', function () {
              if (this.options[2].selected == true) {           //判斷第三個選項是否被選定
                     alert('選擇正確!');
              }
       });
 
添加選項
如需動態的添加選項我們有兩種方案:DOM和Option構造函數。
       var option = document.createElement('option');
       option.appendChild(document.createTextNode('北京t'));
       option.setAttribute('value', '北京v')
       city.appendChild(option);
 
使用Option構造函數創建:
var option = new Option('北京t', '北京v');
city.appendChild(option);                                  //IE出現bug
 
使用add()方法來添加選項:
var option = new Option('北京t', '北京v');
city.add(option, 0);                                           //0,表示添加到第一位
 
PS:在DOM規定,add()中兩個參數是必須的,如果不確定索引,那么第二個參數設置null即可,即默認移入最后一個選項。但這是IE中規定第二個參數是可選的,所以設置null表示放入不存在的位置,導致失蹤,為了兼容性,我們傳遞undefined即可兼容。
city.add(option, null);                                       //IE不顯示了
city.add(option, undefined);                               //兼容了
 
移除選項
有三種方式可以移除某一個選項:DOM移除、remove()方法移除和null移除。
city.removeChild(city.options[0]);                      //DOM移除
city.remove(0);                                                //remove()移除,推薦
city.options[0] = null;                                       //null移除
 
PS:當第一項移除后,下面的項,往上頂,所以不停的移除第一項,即可全部移除。
 
移動選項
如果有兩個選擇框,把第一個選擇框里的第一項移到第二個選擇框里,并且第一個選擇框里的第一項被移除。
var city = fm.elements['city'];                             //第一個選擇框
var info = fm.elements['info'];                           //第二個選擇框
info.appendChild(city.options[0]);                      //移動,被自我刪除
 
 
排列選項
選擇框提供了一個index屬性,可以得到當前選項的索引值,和selectedIndex的區別是,一個是選擇框對象的調用,一個是選項對象的調用。
var option1 = city.options[1];
city.insertBefore(option1, city.options[option1.index - 1]);        //往下移動移位
 
單選按鈕
通過checked屬性來獲取單選按鈕的值。
       for (var i = 0; i < fm.sex.length; i ++) {                    //循環單選按鈕
              if (fm.sex[i].checked == true) {                  //遍歷每一個找出選中的那個
                     alert(fm.sex[i].value);                         //得到值
              }
       }
 
PS:除了checked屬性之外,單選按鈕還有一個defaultChecked按鈕,它獲取的是原本的checked按鈕對象,而不會因為checked的改變而改變。
       if (fm.sex[i].defaultChecked == true) {
              alert(fm.sex[i].value);
       }
 
復選按鈕
通過checked屬性來獲取復選按鈕的值。復選按鈕也具有defaultChecked屬性。
       var love = '';
       for (var i = 0; i < fm.love.length; i ++) {
              if (fm.love[i].checked == true) {
                     love += fm.love[i].value;
              }
       }
       alert(love);
------分隔線----------------------------
30选5开奖查询