本章知识架构
var EventUtil = {
// 添加事件处理程序
addHandler: function(element, type, handler){if (element.addEventListener){element.addEventListener(type, handler, false);
} else if (element.attachEvent){element.attachEvent("on" + type, handler);
} else {element["on" + type] = handler;
}
},
// 检测按键 button 属性
getButton: function(event){if (document.implementation.hasFeature("MouseEvents", "2.0")){return event.button;} else {switch(event.button){
case 0:
case 1:
case 3:
case 5:
case 7:
return 0;
case 2:
case 6:
return 2;
case 4: return 1;
}
}
},
// 获取字符编码
getCharCode: function(event){if (typeof event.charCode == "number"){return event.charCode;} else {return event.keyCode;}
},
// 访问剪贴板中的数据,获取 clipboardData 对象
getClipboardText: function(event){var clipboardData = (event.clipboardData || window.clipboardData);
return clipboardData.getData("text");
},
// 获取事件对象
getEvent: function(event){return event ? event : window.event;},
// 获取相关元素
getRelatedTarget: function(event){if (event.relatedTarget){return event.relatedTarget;} else if (event.toElement){return event.toElement;} else if (event.fromElement){return event.fromElement;} else {return null;}
},
// 获取事件目标
getTarget: function(event){return event.target || event.srcElement;},
// 鼠标滚轮事件的 wheelDelta 属性
getWheelDelta: function(event){if (event.wheelDelta){return (client.engine.opera && client.engine.opera < 9.5 ? -event.wheelDelta : event.wheelDelta);
} else {return -event.detail * 40;}
},
// 阻止默认事件
preventDefault: function(event){if (event.preventDefault){event.preventDefault();
} else {event.returnValue = false;}
},
// 移除事件处理程序
removeHandler: function(element, type, handler){if (element.removeEventListener){element.removeEventListener(type, handler, false);
} else if (element.detachEvent){element.detachEvent("on" + type, handler);
} else {element["on" + type] = null;
}
},
setClipboardText: function(event, value){if (event.clipboardData){event.clipboardData.setData("text/plain", value);
} else if (window.clipboardData){window.clipboardData.setData("text", value);
}
},
// 阻止冒泡事件
stopPropagation: function(event){if (event.stopPropagation){event.stopPropagation();
} else {event.cancelBubble = true;}
}
};
1、表单的基础知识
JavaScript 中,表单对应的则是 HTMLFormElement 类型。HTMLFormElement 继承了 HTMLElement,因而与其他 HTML 元素具有相同的默认属性。它自己下列独有的属性和方法。
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> 元素引用的方式:
-
(1)将它看成与其他元素一样,并为其添加 id 特性,然后再像下面这样使用 getElementById()方法找到它;
var form = document.getElementById("form1");
-
(2)通过 document.forms 可以取得页面中所有的表单。在这个集合中,可以通过数值索引或 name 值来取得特定的表单;
var firstForm = document.forms[0]; // 取得页面中的第一个表单 var myForm = document.forms["form2"]; // 取得页面中名称为 "form2" 的表单
1.1 提交表单
-
(1)使用 <input> 或 <button> 都可以定义提交按钮,只要将其 type 特性的值设置为 ”submit” 即可,而图像按钮则是通过将 <input> 的 type 特性值设置为 ”image” 来定义的。
<!-- 通用提交按钮 --> <input type="submit" value="Submit Form"> <!-- 自定义提交按钮 --> <button type="submit">Submit Form</button> <!-- 图像按钮 --> <input type="image" src="graphic.gif">
-
(2)在 JavaScript 中,以编程方式调用 submit()方法也可以提交表单;
var form = document.getElementById("myForm"); // 提交表单 form.submit();
解决重复提交表单这一问题的办法有两个:
- 在第一次提交表单后就禁用提交按钮,或者利用 onsubmit 事件处理程序取消后续的表单提交操作。
- (3)在以调用 submit()方法的形式提交表单时,不会触发 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;
});
1.2 重置表单
-
(1)使用 type 特性值为 ”reset” 的 <input> 或 <button> 都可以创建重置按钮。用户单击重置按钮重置表单时,会触发 reset 事件。
<!-- 通用重置按钮 --> <input type="reset" value="Reset Form"> <!-- 自定义重置按钮 --> <button type="reset">Reset Form</button>
-
(2)与提交表单一样,也可以通过 JavaScript 来重置表单;
var form = document.getElementById("myForm");
- (3)与调用 submit()方法不同,调用 reset()方法会像单击重置按钮一样触发 reset 事件。
1.3 表单字段
可以像访问页面中的其他元素一样,使用原生 DOM 方法访问表单元素。此外,每个表单都有 elements 属性,该属性是表单中所有表单元素(字段)的集合。这个 elements 集合是一个有序列表,其中包含着表单中的所有字段,例如 <input>、<textarea>、<button> 和 <fieldset>。
var form = document.getElementById("form1");
// 取得表单中的第一个字段
var field1 = form.elements[0];
// 取得名为 "textbox1" 的字段
var field2 = form.elements["textbox1"];
// 取得表单中包含的字段的数量
var fieldCount = form.elements.length;
如果有多个表单控件都在使用一个 name(如单选按钮),那么就会返回以该 name 命名的一个 NodeList。
<form method="post" id="myForm">
<ul>
<li><input type="radio" name="color" value="red">Red</li>
<li><input type="radio" name="color" value="green">Green</li>
<li><input type="radio" name="color" value="blue">Blue</li>
</ul>
</form>
var form = document.getElementById("myForm");
var colorFields = form.elements["color"];
alert(colorFields.length); //3
var firstColorField = colorFields[0];
var firstFormField = form.elements[0];
alert(firstColorField === firstFormField); //true
1.3.1 共有的表单字段属性
除了 <fieldset> 元素之外,所有表单字段都拥有相同的一组属性。表单字段共有的属性如下。
disabled:布尔值,表示当前字段是否被禁用。 form:指向当前字段所属表单的指针;只读。 name:当前字段的名称。 readOnly:布尔值,表示当前字段是否只读。 tabIndex:表示当前字段的切换(tab)序号。 type:当前字段的类型,如 "checkbox"、"radio",等等。 value:当前字段将被提交给服务器的值。对文件字段来说,这个属性是只读的,包含着文件在计算机中的路径
除了 form 属性之外,可以通过 JavaScript 动态修改其他任何属性。
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";
除了 <fieldset> 之外,所有表单字段都有 type 属性。对于 <input> 元素,这个值等于 HTML 特性 type 的值。对于其他元素,这个 type 属性的值如下表所列。
1.3.2 共有的表单字段方法
每个表单字段都有两个方法:focus()
和 blur()
;
-
focus()
方法用于将浏览器的焦点设置到表单字段,即激活表单字段,使其可以响应键盘事件。 -
HTML5 为表单字段新增了一个 autofocus 属性。在支持这个属性的浏览器中,只要设置这个属性, 不用 JavaScript 就能自动把焦点移动到相应字段。
<input type="text" autofocus>
-
blur()
方法,它的作用是从元素中移走焦点。在调用 blur()方法时,并不会把焦点转移到某个特定的元素上;仅仅是将焦点从调用这个方法的元素上面移走而已。
1.3.3 共有的表单字段事件
除了支持鼠标、键盘、更改和 HTML 事件之外,所有表单字段都支持下列 3 个事件。
-
blur:
当前字段失去焦点时触发。 -
change:
对于 <input> 和 <textarea> 元素,在它们失去焦点且 value 值改变时触发;对于 <select> 元素,在其选项改变时触发。 -
focus:
当前字段获得焦点时触发。
2、文本框脚本
在 HTML 中,有两种方式来表现文本框:一种是使用 <input> 元素的单行文本框,另一种是使用 <textarea> 的多行文本框。
-
(1)要表现文本框,必须将 <input> 元素的 type 特性设置为 ”text”。而通过设置 size 特性,可以指定文本框中能够显示的字符数。通过 value 特性,可以设置文本框的初始值,而 maxlength 特性则用于指定文本框可以接受的最大字符数。
// 创建一个文本框,让它能够显示 25 个字符,但输入不能超过 50 个字符 <input type="text" size="25" maxlength="50" value="initial value">
-
(2)<textarea> 元素则始终会呈现为一个多行文本框。要指定文本框的大小,可以使用 rows 和 cols 特性。其中,rows 特性指定的是文本框的字符行数,而 cols 特性指定的是文本框的字符列数。<textarea> 的初始值必须要放在 <textarea> 和 </textarea> 之间。
<textarea rows="25" cols="5">initial value</textarea>
2.1 选择文本
上述两种文本框都支持 select()方法,这个方法用于选择文本框中的所有文本。在调用 select()
方法时,大多数浏览器(Opera 除外)都会将焦点设置到文本框中。这个方法不接受参数,可以在任何时候被调用。
var textbox = document.forms[0].elements["textbox1"];
textbox.select();
2.1.1 选择 (select) 事件
与 select()
方法对应的,是一个 select 事件。在选择了文本框中的文本时,就会触发 select 事件。另外,在调用 select()方法时也会触发 select 事件。
var textbox = document.forms[0].elements["textbox1"];
EventUtil.addHandler(textbox, "select", function(event){var alert("Text selected" + textbox.value);
});
2.1.2 取得选择的文本
(1)采取的办法是添加两个属性:selectionStart
和 selectionEnd
。这两个属性中保存的是基于 0 的数值,表示所选择文本的范围(即文本选区开头和结尾的偏移量)。
function getSelectedText(textbox){return textbox.value.substring(textbox.selectionStart, textbox.selectionEnd);
}
因 为 substring() 方 法 基 于 字 符 串 的 偏 移 量 执 行 操 作,所 以 将 selectionStart 和 selectionEnd 直接传给它就可以取得选中的文本。
(2)IE8 及更早的版本中有一个 document.selection
对象,其中保存着用户在整个文档范围内选择的文本信息。
// 获取选中的文本
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;
}
}
2.1.3 选择部分文本
(1)所有文本框都有一个 setSelectionRange() 方法
。这个方法接收两个参数:要选择的第一个字符的索引和要选择的最后一个字符之后的字符的索引(类似于 substring() 方法的两个参数)。【IE9、Firefox、Safari、Chrome 和 Opera】
textbox.value = "Hello world!"
// 选择所有文本
textbox.setSelectionRange(0, textbox.value.length); //"Hello world!"
// 选择前 3 个字符
textbox.setSelectionRange(0, 3); //"Hel"
// 选择第 4 到第 6 个字符
textbox.setSelectionRange(4, 7); //"o w"
(2)IE 在所有文本框上提供的 createTextRange()方法创建一个范围,并将其放在恰当的位置上。然后,再使用 moveStart()和 moveEnd()这两个范围方法将范围移动到位。不过,在调用这两个方法以前,还必须使用 collapse()将范围折叠到文本框的开始位置。此时,moveStart()将范围的起点和终点移动到了相同的位置,只要再给 moveEnd()传入要选择的字符总数即可。最后一步,就是使用范围的 select()方法选择文本。【IE8 及更早版本】
textbox.value = "Hello world!";
var range = textbox.createTextRange();
// 选择所有文本
range.collapse(true);
range.moveStart("character", 0);
range.moveEnd("character", textbox.value.length); //"Hello world!"
range.select();
// 选择前 3 个字符
range.collapse(true);
range.moveStart("character", 0);
range.moveEnd("character", 3);
range.select(); //"Hel"
// 选择第 4 到第 6 个字符
range.collapse(true);
range.moveStart("character", 4);
range.moveEnd("character", 3);
range.select(); //"o w"
(3)跨浏览器实现选择部分文本,可以将上述两个方案组合起来。
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()函数接收三个参数:要操作的文本框、要选择文本中第一个字符的索引和要选择文本中最后一个字符之后的索引。首先,函数测试了文本框是否包含 setSelectionRange()方法。如果有,则使用该方法。否则,检测文本框是否支持 createTextRange()方法。如果支持,则通过创建范围来实现选择。最后一步,就是为文本框设置焦点,以便用户看到文本框中选择的文本。可以像下面这样使用 selectText()方法。
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
2.2 过滤输入
2.2.1 屏蔽字符
有时候,我们需要用户输入的文本中包含或不包含某些字符。如果只想屏蔽特定的字符,则需要检测 keypress 事件对应的字符编码,然后再决定如何响应。例如,下列代码只允许用户输入数值。
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);
}
});
2.2.2 操作剪切板
下列就是 6 个剪贴板事件:
-
beforecopy
:在发生复制操作前触发。 -
copy
:在发生复制操作时触发。 -
beforecut
:在发生剪切操作前触发。 -
cut
:在发生剪切操作时触发。 -
beforepaste
:在发生粘贴操作前触发。 -
paste
:在发生粘贴操作时触发。
要访问剪贴板中的数据,可以使用 clipboardData
对象。这个 clipboardData 对象有三个方法:getData()
、setData()
和 clearData()
。其中,getData() 用于从剪贴板中取得数据,它接受一个参数,即要取得的数据的格式;setData()方法的第一个参数也是数据类型,第二个参数是要放在剪贴板中的文本。
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);
}
},
}
2.3 自动切换焦点
使用 JavaScript 可以从多个方面增强表单字段的易用性。其中,最常见的一种方式就是在用户填写完当前字段时,自动将焦点切换到下一个字段。这种“自动切换焦点”的功能,可以通过下列代码实现:
(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);
})();
开始的 tabForward()函数是实现“自动切换焦点”的关键所在。这个函数通过比较用户输入的值与文本框的 maxlength 特性,可以确定是否已经达到最大长度。如果这两个值相等(因为浏览器最终会强制它们相等,因此用户绝不会多输入字符),则需要查找表单字段集合,直至找到下一个文本框。找到下一个文本框之后,则将焦点切换到该文本框。然后,我们把这个函数指定为每个文本框的 onkeyup 事件处理程序。由于 keyup 事件会在用户输入了新字符之后触发,所以此时是检测文本框中内容长度的最佳时机。这样一来,用户在填写这个简单的表单时,就不必再通过按制表键切换表单字段和提交表单了。
2.4 HTML5 约束验证 API
2.4.1 必填字段
(1)第一种情况是在表单字段中指定了 required
属性
<input type="text" name="username" required>
(2)在 JavaScript 中,通过对应的 required 属性,可以检查某个表单字段是否为必填字段。
var isUsernameRequired = document.forms[0].elements["username"].required;
// 使用下面这行代码可以测试浏览器是否支持 required 属性。var isRequiredSupported = "required" in document.createElement("input");
2.4.2 其他输入类型
- (1)HTML5 为 <input> 元素的 type 属性又增加了几个值。这些新的类型不仅能反映数据类型的信息,而且还能提供一些默认的验证功能。其中,
"email"
和"url"
是两个得到支持最多的类型. -
(2)要检测浏览器是否支持这些新类型,可以在 JavaScript 创建一个 <input> 元素,然后将 type 属性设置为 ”email” 或 ”url”,最后再检测这个属性的值。不支持它们的旧版本浏览器会自动将未知的值设置为 ”text”,而支持的浏览器则会返回正确的值。
var input = document.createElement("input"); input.type = "email"; var isEmailSupported = (input.type == "email");
2.4.3 数值范围
HTML5 还定义了另外几个输入元素。这几个元素都要求填写某种基于数字的值:"number"、"range"、"datetime"、"datetime-local"、"date"、"month"、"week",还有 "time"。
- 对所有这些数值类型的输入元素,可以指定
min 属性
(最小的可能值)、max 属性
(最大的可能值)和step 属性
(从 min 到 max 的两个刻度间的差值)。
// 让用户只能输入 0 到 100 的值,而且这个值必须是 5 的倍数
<input type="number" min="0" max="100" step="5" name="count">
以上这些属性在 JavaScript 中都能通过对应的元素访问(或修改)。此外,还有两个方法:stepUp()
和 stepDown()
,都接收一个可选的参数:要在当前值基础上加上或减去的数值。
input.stepUp(); // 加 1
input.stepUp(5); // 加 5
input.stepDown(); // 减 1
input.stepDown(10); // 减 10
2.4.4 输入模式
HTML5 为文本字段新增了 pattern 属性
。这个属性的值是一个正则表达式,用于匹配文本框中的值。
// 如果只想允许在文本字段中输入数值,可以像下面的代码一样应用约束:<input type="text" pattern="\d+" name="count">
// 在 JavaScript 中可以通过 pattern 属性访问模式。var pattern = document.forms[0].elements["count"].pattern;
// 使用以下代码可以检测浏览器是否支持 pattern 属性。var isPatternSupported = "pattern" in document.createElement("input");
2.4.5 检测有效性
使用 checkValidity()方法
可以检测表单中的某个字段是否有效。所有表单字段都有个方法,如果字段的值有效,这个方法返回 true,否则返回 false。
if (document.forms[0].elements[0].checkValidity()){// 字段有效,继续} else {// 字段无效}
与 checkValidity()方法简单地告诉你字段是否有效相比,validity 属性
则会告诉你为什么字段有效或无效。这个对象中包含一系列属性,每个属性会返回一个布尔值。
- customError:如果设置了 setCustomValidity(),则为 true,否则返回 false。
- patternMismatch:如果值与指定的 pattern 属性不匹配,返回 true。
- rangeOverflow:如果值比 max 值大,返回 true。
- rangeUnderflow:如果值比 min 值小,返回 true。
- stepMisMatch:如果 min 和 max 之间的步长值不合理,返回 true。
- tooLong:如果值的长度超过了 maxlength 属性指定的长度,返回 true。有的浏览器(如 Firefox 4)会自动约束字符数量,因此这个值可能永远都返回 false。
- typeMismatch:如果值不是 ”mail” 或 ”url” 要求的格式,返回 true。
- valid:如果这里的其他属性都是 false,返回 true。checkValidity()也要求相同的值。
- valueMissing:如果标注为 required 的字段中没有值,返回 true。
2.4.6 禁用验证
通过设置 novalidate
属性,可以告诉表单不进行验证。
<form method="post" action="signup.php" novalidate>
<!-- 这里插入表单元素 -->
</form>
// 在 JavaScript 中使用 noValidate 属性可以取得或设置这个值,如果这个属性存在,值为 true,如果不存在,值为 false。document.forms[0].noValidate = true; // 禁用验证
如果一个表单中有多个提交按钮,为了指定点击某个提交按钮不必验证表单,可以在相应的按钮上添加 formnovalidate
属性。
<form method="post" action="foo.php">
<!-- 这里插入表单元素 -->
<input type="submit" value="Regular Submit">
<input type="submit" formnovalidate name="btnNoValidate"
value="Non-validating Submit">
</form>
// 使用 JavaScript 也可以设置这个属性。// 禁用验证
document.forms[0].elements["btnNoValidate"].formNoValidate = true;
3、选择框脚本
选择框是通过 <select> 和 <option> 元素创建的。为了方便与这个控件交互,除了所有表单字段共有的属性和方法外,HTMLSelectElement 类型还提供了下列属性和方法。
- add(newOption, relOption):向控件中插入新 <option> 元素,其位置在相关项(relOption)之前。
- multiple:布尔值,表示是否允许多项选择;等价于 HTML 中的 multiple 特性。
- options:控件中所有 <option> 元素的 HTMLCollection。
- remove(index):移除给定位置的选项。
- selectedIndex:基于 0 的选中项的索引,如果没有选中项,则值为 -1。对于支持多选的控件,只保存选中项中第一项的索引。
- size:选择框中可见的行数;等价于 HTML 中的 size 特性;
选择框的 type 属性不是 ”select-one”,就是 ”select-multiple”,这取决于 HTML 代码中有没有 multiple 特性。选择框的 value 属性由当前选中项决定,相应规则如下。
- 如果没有选中的项,则选择框的 value 属性保存空字符串。
- 如果有一个选中项,而且该项的 value 特性已经在 HTML 中指定,则选择框的 value 属性等于选中项的 value 特性。即使 value 特性的值是空字符串,也同样遵循此条规则。
- 如果有一个选中项,但该项的 value 特性在 HTML 中未指定,则选择框的 value 属性等于该项的文本。
- 如果有多个选中项,则选择框的 value 属性将依据前两条规则取得第一个选中项的值。
在 DOM 中,每个 <option> 元素都有一个 HTMLOptionElement 对象表示。为便于访问数据,HTMLOptionElement 对象添加了下列属性:
- index:当前选项在 options 集合中的索引。
- label:当前选项的标签;等价于 HTML 中的 label 特性。
- selected:布尔值,表示当前选项是否被选中。将这个属性设置为 true 可以选中当前选项。
- text:选项的文本。
- value:选项的值(等价于 HTML 中的 value 特性)。
推荐使用选项属性取得选择框中的文本和值。
var selectbox = document.forms[0]. elements["location"];
// 推荐
var text = selectbox.options[0].text; // 选项的文本
var value = selectbox.options[0].value; // 选项的值
3.1 选择选项
(1)对于只允许选择一项的选择框,访问选中项的最简单方式,就是使用选择框的 selectedIndex 属性
;
var selectedOption = selectbox.options[selectbox.selectedIndex];
(2)另一种选择选项的方式,就是取得对某一项的引用,然后将其 selected 属性
设置为 true。
// 下面的代码会选中选择框中的第一项:selectbox.options[0].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;
}
3.2 添加选项
(1)第一种方式就是使用如下所示的DOM 方法
。
var newOption = document.createElement("option");
newOption.appendChild(document.createTextNode("Option text"));
newOption.setAttribute("value", "Option value");
selectbox.appendChild(newOption);
(2)第二种方式是使用 Option 构造函数
来创建新选项,Option 构造函数接受两个参数:文本(text)和值(value);第二个参数可选。
var newOption = new Option("Option text", "Option value");
selectbox.appendChild(newOption); // 在 IE8 及之前版本中有问题
(3)第三种添加新选项的方式是使用选择框的 add()方法
。DOM 规定这个方法接受两个参数:要添加的新选项和将位于新选项之后的选项。如果想在列表的最后添加一个选项,应该将第二个参数设置为 null。要想编写跨浏览器的代码,为第二个参数传入 undefined,就可以在所有浏览器中都将新选项插入到列表最后了。
var newOption = new Option("Option text", "Option value");
selectbox.add(newOption, undefined); // 最佳方案
3.3 移除选项
(1)首先,可以使用 DOM 的 removeChild()
方法,为其传入要移除的选项
selectbox.removeChild(selectbox.options[0]); // 移除第一个选项
(2)可以使用选择框的 remove()
方法。这个方法接受一个参数,即要移除选项的索引
selectbox.remove(0); // 移除第一个选项
(3)最后一种方式,就是将相应选项设置为 null
selectbox.options[0] = null; // 移除第一个选项
// 要清除选择框中所有的项
function clearSelectbox(selectbox){for(var i=0, len=selectbox.options.length; i < len; i++){selectbox.remove(i);
}
}
3.4 移动和重排选项
(1) DOM 的 appendChild()
方法,就可以将第一个选择框中的选项直接移动到第二个选择框中。如果为 appendChild()方法传入一个文档中已有的元素,那么就会先从该元素的父节点中移除它,再把它添加到指定的位置。
(2)要将选择框中的某一项移动到特定位置,最合适的 DOM 方法就是 insertBefore()
;appendChild()方法只适用于将选项添加到选择框的最后。
4、表单序列化
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("&");
}
5、富文本编辑
所见即所得。这一技术
的本质,就是在页面中嵌入一个包含空 HTML 页面的 iframe。通过设置 designMode 属性
,这个空白的 HTML 页面可以被编辑,而编辑对象则是该页面 <body> 元素的 HTML 代码。designMode 属性有两个可能的值:“off”(默认值)和 ”on”。
5.1 使用 contenteditable 属性
- 另一种编辑富文本内容的方式是使用名为
contenteditable
的特殊属性,这个属性也是由 IE 最早实现的。可以把 contenteditable 属性应用给页面中的任何元素,然后用户立即就可以编辑该元素。 - contenteditable 属性有三个可能的值:“true” 表示打开、“false” 表示关闭,“inherit” 表示从父元素那里继承(因为可以在 contenteditable 元素中创建或删除元素)。
5.2 操作富文本
- 与富文本编辑器交互的主要方式,就是使用
document.execCommand()
。可以为 document.execCommand()方法传递 3 个参数:要执行的命令名称、表示浏览器是否应该为当前命令提供用户界面的一个布尔值和执行命令必须的一个值(如果不需要值,则传递 null)。为了确保跨浏览器的兼容性,第二个参数应该始终设置为 false,因为 Firefox 会在该参数为 true 时抛出错误。
// 可以在任何时候使用这些命令来修改富文本区域的外观,如下面的例子所示。// 转换粗体文本
frames["richedit"].document.execCommand("bold", false, null);
// 转换斜体文本
frames["richedit"].document.execCommand("italic", false, null);
// 创建指向 www.wrox.com 的链接
frames["richedit"].document.execCommand("createlink", false,
"http://www.wrox.com");
// 格式化为 1 级标题
frames["richedit"].document.execCommand("formatblock", false, "<h1>");
- 除了命令之外,还有一些与命令相关的方法。第一个方法就是
queryCommandEnabled()
,可以用它来检测是否可以针对当前选择的文本,或者当前插入字符所在位置执行某个命令。这个方法接收一个参数,即要检测的命令。如果当前编辑区域允许执行传入的命令,这个方法返回 true,否则返回 false。 - 另外,
queryCommandState()
方法用于确定是否已将指定命令应用到了选择的文本。 - 最后一个方法是
queryCommandValue()
,用于取得执行命令时传入的值(即前面例子中传给 document.execCommand() 的第三个参数)。
5.3 富文本选区
在富文本编辑器中,使用框架(iframe)的 getSelection()方法,可以确定实际选择的文本。这个方法是 window 对象和 document 对象的属性,调用它会返回一个表示当前选择文本的 Selection 对象。每个 Selection 对象都有下列属性:
- anchorNode:选区起点所在的节点。
- anchorOffset:在到达选区起点位置之前跳过的 anchorNode 中的字符数量。
- focusNode:选区终点所在的节点。
- focusOffset:focusNode 中包含在选区之内的字符数量。
- isCollapsed:布尔值,表示选区的起点和终点是否重合。
- rangeCount:选区中包含的 DOM 范围的数量。
Selection 对象还有下列方法:
- addRange(range):将指定的 DOM 范围添加到选区中。
- collapse(node, offset):将选区折叠到指定节点中的相应的文本偏移位置。
- collapseToEnd():将选区折叠到终点位置。
- collapseToStart():将选区折叠到起点位置。
- containsNode(node):确定指定的节点是否包含在选区中。
- deleteFromDocument():从文档中删除选区中的文本,与 document.execCommand(“delete”,false, null)命令的结果相同。
- extend(node, offset):通过将 focusNode 和 focusOffset 移动到指定的值来扩展选区。
- getRangeAt(index):返回索引对应的选区中的 DOM 范围。
- removeAllRanges():从选区中移除所有 DOM 范围。实际上,这样会移除选区,因为选区中至少要有一个范围。
- reomveRange(range):从选区中移除指定的 DOM 范围。
- selectAllChildren(node):清除选区并选择指定节点的所有子节点。
- toString():返回选区所包含的文本内容
5.4 表单与富文本
由于以这种方式构建的富文本编辑器并不是一个表单字段,因此在将其内容提交给服务器之前,必须将 iframe 或 contenteditable 元素中的 HTML 复制到一个表单字段中。
下面就是通过
// 表单的 onsubmit 事件处理程序实现上述操作的代码。EventUtil.addHandler(form, "submit", function(event){event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
target.elements["comments"].value = frames["richedit"].document.body.innerHTML;
});