1. 程式人生 > >《Javascript 高階程式設計(第三版)》筆記0x1A 表單指令碼

《Javascript 高階程式設計(第三版)》筆記0x1A 表單指令碼

目錄

表單的基礎知識

     提交表單

     重置表單

     表單欄位

        共有的表單欄位屬性

        共有的表單欄位方法

        共有的表單欄位事件

文字框指令碼

    選擇文字

        選擇(select)事件

        取得選擇的文字

        選擇部分文字

    過濾輸入

        遮蔽字元

        操作剪貼簿

    自動切換焦點

     HTML5 約束驗證API

        必填欄位

        其他輸入型別

        數值範圍

        輸入模式

        檢測有效性

        禁用驗證

   選擇框指令碼

        選擇選項

        新增選項

        移除選項

    移動和重排選項

表單序列化

富文字編輯


表單的基礎知識

        在 HTML 中,表單是由<form>元素來表示的,而在 JavaScript 中,表單對應的則是 HTMLFormElement 型別。 HTMLFormElement 繼承了 HTMLElement,因而與其他 HTML 元素具有相同的預設屬性。不過, HTMLFormElement 也有它自己下列獨有的屬性和方法。
        acceptCharset:伺服器能夠處理的字符集;等價於 HTML 中的 accept-charset 特性。
        action:接受請求的 URL;等價於 HTML 中的 action 特性。
        elements:表單中所有控制元件的集合(HTMLCollection)。
        enctype:請求的編碼型別;等價於 HTML 中的 enctype 特性。
        length:表單中控制元件的數量。
        method:要傳送的 HTTP 請求型別,通常是"get"或"post";等價於 HTML 的 method 特性。
        name:表單的名稱;等價於 HTML 的 name 特性。
        reset():將所有表單域重置為預設值。
        submit():提交表單。
        target:用於傳送請求和接收響應的視窗名稱;等價於 HTML 的 target 特性。

///取得<form>元素
var form = document.getElementById("form1");

var firstForm = document.forms[0]; //取得頁面中的第一個表單
var myForm = document.forms["form2"]; //取得頁面中名稱為"form2"的表單

     提交表單

<!-- 通用提交按鈕 -->
<input type="submit" value="Submit Form">
<!-- 自定義提交按鈕 -->
<button type="submit">Submit Form</button>
<!-- 影象按鈕 -->
<input type="image" src="graphic.gif">

        瀏覽器會在將請求傳送給伺服器之前觸發 submit 事件。這樣就有機會驗證表單資料,並據以決定是否允許表單提交。

var form = document.getElementById("myForm");
EventUtil.addHandler(form, "submit", function(event){
    //取得事件物件
    event = EventUtil.getEvent(event);
    //阻止預設事件
    EventUtil.preventDefault(event);
});

//通過JavaScript提交表單,不會觸發submit事件,因此要記得在呼叫此方法之前先驗證表單資料。
var form = document.getElementById("myForm");
//提交表單
form.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);
});

//通過 JavaScript 來重置表單,呼叫 reset()方法會像單擊重置按鈕一樣觸發 reset 事件
var form = document.getElementById("myForm");
//重置表單
form.reset();

     表單欄位

        每個表單都有elements 屬性,該屬性是表單中所有表單元素(欄位)的集合。這個 elements 集合是一個有序列表,其中包含著表單中的所有欄位,例如<input>、 <textarea>、 <button>和<fieldset>。每個表單欄位在 elements 集合中的順序,與它們出現在標記中的順序相同,可以按照位置和 name 特性來訪問它們。

var form = document.getElementById("form1");
//取得表單中的第一個欄位
var field1 = form.elements[0];
//取得名為"textbox1"的欄位
//如果有多個表單控制元件都在使用一個 name(如單選按鈕),那麼就會返回以該 name 命名的一個NodeList
var field2 = form.elements["textbox1"];
//取得表單中包含的欄位的數量
var fieldCount = form.elements.length;

        共有的表單欄位屬性

    除了<fieldset>元素之外,所有表單欄位都擁有相同的一組屬性。表單欄位共有的屬性如下。
        disabled:布林值,表示當前欄位是否被禁用。
        form:指向當前欄位所屬表單的指標;只讀。
        name:當前欄位的名稱。
        readOnly:布林值,表示當前欄位是否只讀。
        tabIndex:表示當前欄位的切換(tab)序號。
        type:當前欄位的型別,如"checkbox"、 "radio",等等。
        value:當前欄位將被提交給伺服器的值。對檔案欄位來說,這個屬性是隻讀的,包含著檔案在計算機中的路徑

var form = document.getElementById("myForm");
var field = form.elements[0];
//修改 value 屬性
field.value = "Another value";
//檢查 form 屬性的值
alert(field.form === form); //true
//把焦點設定到當前欄位
field.focus();
//禁用當前欄位
field.disabled = true;
//修改 type 屬性(不推薦,但對<input>來說是可行的)
field.type = "checkbox";

        不能通過 onclick 事件處理程式來實現一些功能,原因是不同瀏覽器之間存在“時差”:有的瀏覽器會在觸發表單的 submit 事件之前觸發 click 事件,而有的瀏覽器則相反。對於先觸發 click 事件的瀏覽器,意味著會在提交發生之前禁用按鈕,結果永遠都不會提交表單。因此,最好是通過 submit 事件來禁用提交按鈕。

//避免多次提交表單
EventUtil.addHandler(form, "submit", function(event){
	event = EventUtil.getEvent(event);
	var target = EventUtil.getTarget(event);
	//取得提交按鈕
	var btn = target.elements["submit-btn"];
	//禁用它
	btn.disabled = true;
});

        共有的表單欄位方法

        每個表單欄位都有兩個方法: focus()和 blur()。focus()方法用於將瀏覽器的焦點設定到表單欄位,即啟用表單欄位,使其可以響應鍵盤事件。blur()方法,它的作用是從元素中移走焦點。在呼叫 blur()方法時,並不會把焦點轉移到某個特定的元素上;僅僅是將焦點從呼叫這個方法的元素上面移走而已。

        共有的表單欄位事件

    除了支援滑鼠、鍵盤、更改和 HTML 事件之外,所有表單欄位都支援下列 3 個事件。
        blur:當前欄位失去焦點時觸發。
        change:對於<input>和<textarea>元素,在它們失去焦點且 value 值改變時觸發;對於
<select>元素,在其選項改變時觸發。
        focus:當前欄位獲得焦點時觸發

文字框指令碼

<input type="text" size="25" maxlength="50" value="initial value">
<textarea rows="25" cols="5">initial value</textarea>

    選擇文字

         上述兩種文字框都支援 select()方法,這個方法用於選擇文字框中的所有文字。在呼叫 select()方法時,大多數瀏覽器(Opera 除外)都會將焦點設定到文字框中。這個方法不接受引數,可以在任何時候被呼叫。

var textbox = document.forms[0].elements["textbox1"];
textbox.select();

//在文字框獲得焦點時選擇其所有文字
EventUtil.addHandler(textbox, "focus", function(event){
	event = EventUtil.getEvent(event);
	var target = EventUtil.getTarget(event);
	target.select();
});

        選擇(select)事件

var textbox = document.forms[0].elements["textbox1"];
EventUtil.addHandler(textbox, "select", function(event){
	var alert("Text selected" + textbox.value);
});

        取得選擇的文字

//取得使用者在文字框中選擇的文字
function getSelectedText(textbox){
	return textbox.value.substring(textbox.selectionStart, textbox.selectionEnd);
}

        選擇部分文字

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();
}

textbox.value = "Hello world!"
//選擇所有文字
selectText(textbox, 0, textbox.value.length); //"Hello world!"
//選擇前 3 個字元
selectText(textbox, 0, 3); //"Hel"
//選擇第 4 到第 6 個字元
selectText(textbox, 4, 7); //"o w"

    過濾輸入

        遮蔽字元

//遮蔽所有按鍵操作
EventUtil.addHandler(textbox, "keypress", function(event){
	event = EventUtil.getEvent(event);
	EventUtil.preventDefault(event);
});

//只允許使用者輸入數值
EventUtil.addHandler(textbox, "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 &&!event.ctrlKey){
		EventUtil.preventDefault(event);
	}
});

        操作剪貼簿

var EventUtil = {
	//省略的程式碼
	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);
		}
	},
	//省略的程式碼
};

    自動切換焦點

        使用 JavaScript 可以從多個方面增強表單欄位的易用性。其中,最常見的一種方式就是在使用者填寫完當前欄位時,自動將焦點切換到下一個欄位。

<input type="text" name="tel1" id="txtTel1" maxlength="3">
<input type="text" name="tel2" id="txtTel2" maxlength="3">
<input type="text" name="tel3" id="txtTel3" maxlength="4">
(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

        必填欄位

<input type="text" name="username" required>
var isUsernameRequired = document.forms[0].elements["username"].required;

var isRequiredSupported = "required" in document.createElement("input");

        其他輸入型別

<input type="email" name ="email">
<input type="url" name="homepage">
var input = document.createElement("input");
input.type = "email";

var isEmailSupported = (input.type == "email");

        數值範圍

<!--只能輸入 0 到 100 的值,而且這個值必須是 5 的倍數-->
<input type="number" min="0" max="100" step="5" name="count">

        輸入模式

<!--只允許在文字欄位中輸入數值-->
<input type="text" pattern="\d+" name="count">

        檢測有效性

//使用 checkValidity()方法可以檢測表單中的某個欄位是否有效。
if (document.forms[0].elements[0].checkValidity()){
	//欄位有效,繼續
} else {
	//欄位無效
}
//validity屬性可說明為什麼欄位有效或無效
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>

   選擇框指令碼

        選擇選項

//////////////////用選擇框的 selectedIndex 屬性////////////////////////////
var selectedIndex = selectbox.selectedIndex;
var selectedOption = selectbox.options[selectedIndex];
alert("Selected index: " + selectedIndex + "\nSelected text: " +
	selectedOption.text + "\nSelected value: " + selectedOption.value);
	
///////////取得對某一項的引用,然後將其 selected 屬性設定為 true///////////
function getSelectedOptions(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;
}

var selectbox = document.getElementById("selLocation");
var selectedOptions = getSelectedOptions(selectbox);
var message = "";
for (var i=0, len=selectedOptions.length; i < len; i++){
	message += "Selected index: " + selectedOptions[i].index +
	"\nSelected text: " + selectedOptions[i].text +
	"\nSelected value: " + selectedOptions[i].value + "\n\n";
}
alert(message);

        新增選項

//DOM 方法
var newOption = document.createElement("option");
newOption.appendChild(document.createTextNode("Option text"));
newOption.setAttribute("value", "Option value");
selectbox.appendChild(newOption);

//使用 Option 建構函式來建立新選項
var newOption = new Option("Option text", "Option value");
selectbox.appendChild(newOption); //在 IE8 及之前版本中有問題

//使用選擇框的 add()方法
var newOption = new Option("Option text", "Option value");
selectbox.add(newOption, undefined); //最佳方案

        移除選項

//DOM 的 removeChild()方法
selectbox.removeChild(selectbox.options[0]); //移除第一個選項

//選擇框的 remove()方法
selectbox.remove(0); //移除第一個選項

//將相應選項設定為 null
selectbox.options[0] = null; //移除第一個選項

//清除選擇框中所有的項
function clearSelectbox(selectbox){
	for(var i=0, len=selectbox.options.length; i < len; i++){
		selectbox.remove(i);
	}
}

    移動和重排選項

//將第一個選擇框中的第一個選項移動到第二個選擇框
var selectbox1 = document.getElementById("selLocations1");
var selectbox2 = document.getElementById("selLocations2");
selectbox2.appendChild(selectbox1.options[0]);

//在選擇框中向前移動一個選項的位置
var optionToMove = selectbox.options[1];
selectbox.insertBefore(optionToMove, selectbox.options[optionToMove.index-1]);

//將選擇框中的選項向後移動一個位置
var optionToMove = selectbox.options[1];
selectbox.insertBefore(optionToMove, selectbox.options[optionToMove.index+2]);

表單序列化

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("&");
}

富文字編輯