一、基础
在 JavaScript
中,表单有它自己独有的属性和方法。
-
acceptCharset
:服务器能够处理的字符集; -
action
:接受请求的URL
; -
elements
:表单中所有控件的集合(HTMLCollection)。 -
enctype
:请求的编码类型; -
length
:表单中控件的数量。 -
method
:要发送的 HTTP 请求类型,通常是"get"
或"post"
; -
name
:表单的名称;。 -
reset()
:将所有表单域重置为默认值。 -
submit()
:提交表单。 -
target
:用于发送请求和接收响应的窗口名称
通过document.forms
可以取得页面中所有的表单。在这个集合中,可以通过数值索引或name
值来取得特定的表单,也可以通过id
、类名来获取。
提交表单
<!-- 通用提交按钮 -->
<input type="submit" value="Submit Form">
<!-- 自定义提交按钮 -->
<button type="submit">Submit Form</button>
<!-- 图像按钮 -->
<input type="image" src="graphic.gif">
只要表单中存在上面列出的任何一种按钮,那么在相应表单控件拥有焦点的情况下,按回车键就可以提交该表单(textarea
除外,在文本区中回车是换行),如果没有提交按钮,按回车键则不会提交表单。以这种方式提交表单时,浏览器会在将请求发送给服务器之前触发onsubmit
事件。这样,我们就有机会验证表单数据,并据以决定是否允许表单提交。调用prevetnDefault()
方法阻止表单提交。一般来说,在表单数据无效而不能发送给服务器时,可以使用这一技术。
在JavaScript
中,以编程方式调用submit()
方法也可以提交表单。form.submit();
,在以调用submit()
方法的形式提交表单时,不会触发onsubmit
事件,因此要记得在调用此方法之前先验证表单数据。
为避免用户多次点击按钮重复提交表单,可以在第一次提交表单后就禁用提交按钮,或者利用onsubmit
事件处理程序取消后续的表单提交操作。
重置表单
<!-- 通用重置按钮 -->
<input type="reset" value="Reset Form">
<!-- 自定义重置按钮 -->
<button type="reset">Reset Form</button>
在重置表单时,所有表单字段都会恢复到页面刚加载完毕时的初始值,用户单击重置按钮重置表单时,会触发onreset
事件。也可以使用编程方式来重置表单form.reset()
,与调用submit()
方法不同,调用reset()
方法会像单击重置按钮一样触发onreset
事件。
表单字段
每个表单都有elements
属性,该属性是表单中所有表单元素(字段)的集合,例如<input>
、<textarea>
、<button>
和<fieldset>
,是一个有序列表(不包含非表单控件)。可以按照位置和name
特性来访问它们。
var form = document.getElementById("form1");
//取得表单中的第一个字段
var field1 = form.elements[0];
//取得名为"textbox1"的字段
var field2 = form.elements["textbox1"];
//取得表单中包含的字段的数量
var fieldCount = form.elements.length;
如果有多个表单控件都在使用一个name
(如单选按钮),那么就会返回以该name
命名的一个NodeList
。
-
表单字段属性
-
disabled
:布尔值,表示当前字段是否被禁用。 -
form
:指向当前字段所属表单的指针;只读。 -
name
:当前字段的名称。 -
readOnly
:布尔值,表示当前字段是否只读。 -
tabIndex
:表示当前字段的切换(tab
)序号。 -
type
:当前字段的类型,如"checkbox"
、"radio"
,等等。 -
value
:当前字段将被提交给服务器的值。对文件字段来说,这个属性是只读的,包含着文件在计算机中的路径。
-
可以通过JavaScrip
动态修改属性。
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";
-
表单字段方法
-
focus()
:用于将浏览器的焦点设置到表单字段,即激活表单字段,使其可以响应键盘事件。HTML5
为表单字段新增了一个autofocus
属性。在支持这个属性的浏览器中,只要设置这个属性,不用JavaScript
就能自动把焦点移动到相应字段。 -
blur()
:是从元素中移走焦点。在调用blur()
方法时,并不会把焦点转移到某个特定的元素上;仅仅是将焦点从调用这个方法的元素上面移走而已。
-
-
表单字段事件
-
onfocus
:当前字段获得焦点时触发。 -
onblur
:当前字段失去焦点时触发。 -
onchange
:对于<input>
和<textarea>
元素,在它们失去焦点且value
值改变时触发;对于<select>
元素,在其选项改变时触发。
-
关于blur
和change
事件的关系,并没有严格的规定。在某些浏览器中,blur
事件会先于change
事件发生;而在其他浏览器中,则恰好相反。为此,不能假定这两个事件总会以某种顺序依次触发,这一点要特别注意。
二、文本框脚本
在HTML
中,有两种方式来表现文本框:一种是使用<input>
元素的单行文本框(type
特性设置为"text"
),另一种是使用<textarea>
的多行文本框。
<input>
:通过设置size
特性,可以指定文本框中能够显示的字符数。通过value
特性,可以设置文本框的初始值,而maxlength
特性则用于指定文本框可以接受的最大字符数。
<textarea>
:要指定文本框的大小,可以使用rows
和cols
特性。其中,rows
特性指定的是文本框的字符行数,而cols
特性指定的是文本框的字符列数。
建议使用xxx.value
属性读取或设置文本框的值,不要使用setAttribute()
设置<input>
元素的value
特性,也不要去修改<textarea>
元素的第一个子节点(文本节点)。原因很简单:对value
属性所作的修改,不一定会反映在DOM
中。因此,在处理文本框的值时,最好不要使用DOM
方法。
选择文本
两种文本框都支持select()
方法,这个方法用于选择文本框中的所有文本。在调用select()
方法时formElement.select();
,大多数浏览器(Opera
除外)都会将焦点设置到文本框中。这个方法不接受参数,可以在任何时候被调用。(一般用于当文本框获得焦点,就会选择其中所有的文本)
onselect
事件:在选择了文本框中的文本时,就会触发onselect
事件。现代浏览器只有用户选择了文本(而且要释放鼠标),才会触发onselect
事件。
HTML5
通过一些扩展方案解决了这个问题,以便更顺利地取得选择的文本。该规范采取的办法是添加两个属性:selectionStart
和selectionEnd
。这两个属性中保存的是基于0
的数值,表示所选择文本的范围(即文本选区开头和结尾的偏移量)。因此,要取得用户在文本框中选择的文本,可以使用如下代码。
function getSelectedText(textbox){
// if(typeof textbox.selectionStart == 'number')
return textbox.value.substring(textbox.selectionStart, textbox.selectionEnd);
// ie8之前版本不支持 但是支持document.selection
// if (document.selection){
// return document.selection.createRange().text;
// }
}
- 选择部分文本
所有文本框都有一个setSelectionRange()
方法。这个方法接收两个参数:要选择的第一个字符的索引和要选择的最后一个字符之后的字符的索引。(包头不包尾)
IE8
及更早版本支持使用范围选择部分文本:
1、首先使用IE
在所有文本框上提供的createTextRange()
方法创建一个范围,并将其放在恰当的位置上。
2、使用collapse()
将范围折叠到文本框的开始位置。
3、再使用moveStart()
和moveEnd()
这两个范围方法将范围移动到位。
4、最后一步,就是使用范围的select()
方法选择文本。
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();
//选择第4 到第6 个字符
range.collapse(true);
range.moveStart("character", 4);
range.moveEnd("character", 6);
range.select(); //"o w"
过滤输入
- 屏蔽字符
响应向文本框中插入字符操作的是keypress
事件。因此,可以通过阻止这个事件的默认行为来屏蔽此类字符。比如,下列代码只允许用户输入数值。
textbox.addEventListener("keypress", function(e){
var target = e.target
var charCode = e.charCode
// charCode 属性,这个属性只有在发生keypress 事件时才包含值
// 而且这个值是按下的那个键所代表字符的ASCII 编码
// String.fromCharCode()接收一或多个字符编码,然后将它们转换成一个字符串。
if (!/\d/.test(String.fromCharCode(charCode)) && charCode > 9){
e.preventDefault();
}
});
虽然理论上只应该在用户按下字符键时才触发keypress
事件,但有些浏览器也会对其他键触发此事件。Firefox
和Safari
(3.1
版本以前)会对向上键、向下键、退格键和删除键触发keypress
事件;Safari 3.1
及更新版本则不会对这些键触发keypress
事件。所以加上charCode > 9
这个条件,因为在Firefox
中,所有由非字符键触发的keypress
事件对应的字符编码为0
,而在Safari 3
以前的版本中,对应的字符编码全部为8
。也可以直接使用e.key
(不再使用e.charCode
)来获得用户键入的字符(无需多加判断)。
- 操作剪贴板
除Opera
外,所有浏览器都支持通过JavaScript
访问剪贴板。HTML 5
后来也把剪贴板事件纳入了规范。下列就是6 个剪贴板事件。
-
beforecopy
:在发生复制操作前触发。 -
copy
:在发生复制操作时触发。 -
beforecut
:在发生剪切操作前触发。 -
cut
:在发生剪切操作时触发。 -
beforepaste
:在发生粘贴操作前触发。 -
paste
:在发生粘贴操作时触发。
由于没有针对剪贴板操作的标准,这些事件及相关对象会因浏览器而异。在Safari
、Chrome
和Firefox
中,beforecopy
、beforecut
和beforepaste
事件只会在显示针对文本框的上下文菜单(预期将发生剪贴板事件)的情况下触发。但是,IE
则会在触发copy
、cut
和paste
事件之前先行触发这些事件。至于copy
、cut
和paste
事件,只要是在上下文菜单中选择了相应选项,或者使用了相应的键盘组合键,所有浏览器都会触发它们。取消"before事件"
并不会取消对剪贴板的操作——只有取消copy
、cut
和paste
事件,才能阻止相应操作发生。
要访问剪贴板中的数据,可以使用clipboardData
对象:在IE
中,这个对象是window
对象的属性,可以随时访问clipboardData
对象;而在Firefox 4+
、Safari
和Chrome
中,这个对象是相应event
对象的属性,并且只有在处理剪贴板事件期间clipboardData
对象才有效。
clipboardData
对象有三个方法:getData()
、setData()
和clearData()
。
getData()
用于从剪贴板中取得数据,它接受一个参数,即要取得的数据的格式。在IE
中,有两种数据格式:"text"
和"URL"
。在Firefox
、Safari
和Chrome
中,这个参数是一种MIME
类型(多用途互联网邮箱扩展类型);不过,可以用"text"
代表"text/plain"
。Firefox
、Safari
和Chrome
只允许在onpaste
事件处理程序中访问getData()
方法。
setData()
方法的第一个参数也是数据类型,第二个参数是要放在剪贴板中的文本。对于第一个参数,IE
照样支持"text"
和"URL"
,而Safari
和Chrome
仍然只支持MIME
类型。但是,与getData()
方法不同的是,Safari
和Chrome
的setData()
方法不能识别"text"
类型。这两个浏览器在成功将文本放到剪贴板中后,都会返回true
;否则,返回false
。
var EventUtil = {
getClipboardText: function(event){
var clipboardData = (event.clipboardData || window.clipboardData);
return clipboardData.getData("text");
},
setClipboardText: function(event, value){
if (event.clipboardData){ // safari \ chrome
return event.clipboardData.setData("text/plain", value);
} else if (window.clipboardData){ // IE
return window.clipboardData.setData("text", value);
}
},
};
在需要确保粘贴到文本框中的文本中包含某些字符,或者符合某种格式要求时,能够访问剪贴板是非常有用的。例如,如果一个文本框只接受数值,那么就必须检测粘贴过来的值,以确保有效。在paste
事件中,可以确定剪贴板中的值是否有效,如果无效,则取消默认的行为。
自动切换焦点
通过比较用户输入的值与文本框的maxlength
特性,可以确定是否已经达到最大长度。如果这两个值相等(因为浏览器最终会强制它们相等,因此用户绝不会多输入字符),则需要查找表单字段集合,直至找到下一个文本框。找到下一个文本框之后,则将焦点切换到该文本框。然后,我们把这个函数指定为每个文本框的onkeyup
事件处理程序。由于keyup
事件会在用户输入了新字符之后触发,所以此时是检测文本框中内容长度的最佳时机。
function tabForward(e){
var target = e.target
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;
}
}
}
}
HTML5 约束验证API
为了在将表单提交到服务器之前验证数据,HTML5
新增了一些功能。有了这些功能,即便JavaScript
被禁用或者由于种种原因未能加载,也可以确保基本的验证。浏览器自己会根据标记中的规则执行验证,然后自己显示适当的错误消息(完全不用JavaScript
插手)只有在支持HTML5
这部分内容的浏览器中才有效,这些浏览器有Firefox 4+
、Safari 5+
、Chrome
和Opera 10+
。
就是要在HTML
标记中为特定的字段指定一些约束,然后浏览器才会自动执行表单验证。
- 必填字段
required
属性:<input type="text" name="username" required>
这个属性适用于<input>
、<textarea>
和<select>
字段。在JavaScript
中,通过对应的required
属性,可以检查某个表单字段是否为必填字段。
var isUsernameRequired = document.forms[0].elements["username"].required; // boolean
// 或测试浏览器是否支持 required属性 检查创建的input元素是否存在required属性
var isRequiredSupported = "required" in document.createElement("input");
对于空着的必填字段,不同浏览器有不同的处理方式。Firefox 4
和Opera 11
会阻止表单提交并在相应字段下方弹出帮助框,而Safari(5 之前)
和Chrome(9 之前)
则什么也不做,而且也不阻止表单提交。
- 其他输入类型
<input type="email" name ="email">
<input type="url" name="homepage">
HTML5
新增的input
的type
属性,"email"
类型要求输入的文本必须符合电子邮件地址的模式,而"url"
类型要求输入的文本必须符合URL
的模式。
var input = document.createElement("input");
input.type = "email"; // 先设置 后检查是否设置成功
var isEmailSupported = (input.type == "email"); // 不支持的浏览器 会自动将未知的值设置为"text"
要注意的是,如果不设置required
属性,那么空文本框也会验证通过。另一方面,设置特定的输入类型并不能阻止用户输入无效的值,只是应用某些默认的验证而已。
- 数值范围
HTML5
新增的input
的type
属性关于数值范围的有:
"number"
、"range"
、"datetime"
、"datetimelocal"
、"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()
,都接收一个可选的参数:要在当前值基础上加上或减去的数值。(默认是加或减1
。)
input.stepUp(); //加1
input.stepUp(5); //加5
input.stepDown(); //减1
input.stepDown(10); //减10
- 输入模式
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");
- 检测有效性
使用checkValidity()
方法可以检测表单中的某个字段是否有效。所有表单字段都有个方法,如果字段的值有效,这个方法返回true
,否则返回false
。字段的值是否有效的判断依据是本节前面介绍过的那些约束。要检测整个表单是否有效,可以在表单自身调用checkValidity()
方法。如果所有表单字段都有效,这个方法返回true
;即使有一个字段无效,这个方法也会返回false
。
与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
:如果值不是"email"
或"url"
要求的格式,返回true
。 -
valid
:如果这里的其他属性都是false
,返回true
。checkValidity()
也要求相同的值。 -
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.");
}
}
- 禁用验证
通过设置novalidate
属性,可以告诉表单不进行验证。
<form method="post" action="signup.php" novalidate>
<!--这里插入表单元素-->
</form>
// 在JavaScript 中使用noValidate 属性可以取得或设置这个值
// 如果这个属性存在,值为true,如果不存在,值为false。
document.forms[0].noValidate = true; //禁用验证
如果一个表单中有多个提交按钮,为了指定点击某个提交按钮不必验证表单,可以在相应的按钮上 添加 formnovalidate
属性。也可以使用JavaScript
取得或设置这个属性。
三、选择框脚本
选择框是通过<select>
和<option>
元素创建的。为了方便与这个控件交互,除了所有表单字段共 有的属性和方法外,HTMLSelectElement
类型还提供了下列属性和方法。
-
add(newOption, relOption)
:向控件中插入新<option>
元素,其位置在相关项(relOption)
之前。 -
multiple
:布尔值,表示是否允许多项选择; -
options
:控件中所有<option>
元素的HTMLCollection
。 -
remove(index)
:移除给定位置的选项。 -
selectedIndex
:基于 0 的选中项的索引,如果没有选中项,则值为-1。对于支持多选的控件,只保存选中项中第一项的索引。 -
size
:选择框中可见的行数;
选择框的 type
属性不是"select-one"
,就是"select-multiple"
,这取决于 HTML
代码中有没有 multiple
特性。
<select>
的value
:如果没有选中的options
,则value
为空字符串,如果有选中的options
,则value
的值为被选中的options
的value
属性,如果被选中的options
没有value
属性,则为该options
的文本值。可以通过 option.attributes.value && option.attributes.value.specified
来判断option
元素是否定义了 value
属性。
每个<option>
元素都有以下属性。
-
index
:当前选项在options
集合中的索引。 -
label
:当前选项的标签; -
selected
:布尔值,表示当前选项是否被选中。将这个属性设置为true
可以选中当前选项。 -
text
:选项的文本。 -
value
:选项的值。
建议使用属性访问,不建议使用DOM
方法访问;其他表单字段的 change
事件是在值被修改且焦点离开当前字段时触发,而选择框的 change
事件只要选中了选项就会触发。在未指定 value
特性的情况下,IE8
会返 回空字符串,而 IE9+
、Safari
、Firefox
、Chrome
和 Opera
则会返回与 text
特性相同 的值。
选择选项
访问选中项的最简单方式,就是使用选择框的selectedIndex
属性,如下面的例子所示:
var selectedOption = selectbox.options[selectbox.selectedIndex];
对于可以选择多项的选择框,设置selectedIndex
会导致取消以前的所有选项并选择指定的那一项,而读取selectedIndex
则只会返回选中项中第一项的索引值。另一种选择选项的方式,就是取得对某一项的引用,然后将其selected
属性设置为true
。多选的情况下,可以将多个选项的selected
值设置为true
;而单选框,修改某个选项的selected
属性为true
,则会取消对其他选项的选择。
添加选项
- DOM方法
var newOption = document.createElement("option");
newOption.appendChild(document.createTextNode("Option text"));
newOption.setAttribute("value", "Option value");
selectbox.appendChild(newOption);
- 使用Option 构造函数
// 这一步在兼容DOM的浏览器中会返回一个元素
var newOption = new Option("Option text", "Option value");
selectbox.appendChild(newOption); //在IE8 及之前版本中有问题
selectbox.add(newOption, undefined); //最佳方案
// add接受两个参数(要添加的新选项,相对选项),会将新选项添加到相对选项的前面
// 传值为null或是undefined则将插入到最后
// IE中第二个参数可选,兼容DOM的浏览器要求第二个参数必填。
移除选项
// `removeChild()`
selectbox.removeChild(selectbox.options[0]); //移除第一个选项
// selectElement的`remove()`方法
selectbox.remove(0);
// 这个函数每次只移除选择框中的第一个选项。
// 移除第一个选项后,所有后续选项都会自动向上移动一个位置
// 因此重复移除第一个选项就可以移除所有选项了。
移动和重排选项
如果为appendChild()
方法传入一个文档中已有的元素,那么就会先从该元素的父节点中移除它,再把它添加到指定的位置,这样就可以将第一个选择框中的选项直接移动到第二个选择框中。移动选项与移除选项有一个共同之处,即会重置每一个选项的index
属性。
重排选项次序的过程也十分类似,最好的方式仍然是使用DOM
方法。要将选择框中的某一项移动到特定位置,最合适的DOM
方法就是insertBefore()
;
// 在选择框中向前移动一个选项的位置
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]);
// 如果只加1 相当于没移动
表单序列化
序列化即url?key1=value1&key2=value2
。在JavaScript
中,可以利用表单字段的type
属性,连同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){
// 判断options是否设置了value特性
if (option.hasAttribute){ // DOM兼容的浏览器
optValue = (option.hasAttribute("value") ?
option.value : option.text);
} else { // IE
optValue = (option.attributes["value"].specified ?
option.value : option.text);
}
parts.push(encodeURIComponent(field.name) + "=" +
encodeURIComponent(optValue));
// encodeURIComponent主要用来编码search值
// encodeURI(只转换空格)主要用来编码整个url
}
}
}
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("&");
}
富文本编辑
富文本编辑,又称为WYSIWYG
(What You See Is What You Get
,所见即所得)。包含空HTML
页面的iframe
。通过设置designMode
属性,这个空白的HTML
页面可以被编辑,而编辑对象则是该页面<body>
元素的HTML
代码。
designMode
属性有两个可能的值:"off"
(默认值)和"on"
。在设置为"on"
时,整个文档都会变得可以编辑(显示插入符号),然后就可以像使用字处理软件一样,通过键盘将文本内容加粗、变成斜体,等等。
<iframe name="richedit" style="height:200px;width:200px;" src="./frame.htm"></iframe>
<!-- 也可以把contenteditable 属性应用给页面中的任何元素,然后用户立即就可以编辑该元素 -->
<div class="editable" id="richedit1" contenteditable>1111</div>
<script type="text/javascript">
window.onload= function () {
// 不要在chrome的file环境下尝试 会形成跨域问题。
frames["richedit"].document.designMode = "on";
console.log(frames["richedit"].document.designMode)
}
// iframe_node.contentDocument.designMode = "on";
var div = document.getElementById("richedit1");
div.contentEditable = "true";
// "true"表示打开、"false"表示关闭,"inherit"表示从父元素那里继承
</script>
操作富文本
document.execCommand()
该方法接受三个参数:
1、要执行的命令名称。
2、表示浏览器是否应该为当前命令提供用户界面的一个布尔值(为兼容浏览器,一般统一传false
)
3、执行命令必须的一个值(如果不需要值,则传递null
)。
命令 | 值(第三个参数) | 说明 |
---|---|---|
backcolor |
颜色字符串 | 设置文档的背景颜色 |
bold |
null |
将选择的文本转换为粗体 |
createlink |
URL 字符串 |
将选择的文本转换成一个链接,指向指定的URL
|
cut |
null |
将选择的文本剪切到剪贴板 |
delete |
null |
删除选择的文本 |
fontname |
字体名称 | 将选择的文本修改为指定字体 |
fontsize |
1~7 | 将选择的文本修改为指定字体大小 |
forecolor |
颜色字符串 | 将选择的文本修改为指定的颜色 |
formatblock |
要包围当前文本块的HTML 标签;如<h1>
|
使用指定的HTML 标签来格式化选择的文本块 |
indent |
null |
缩进文本 |
inserthorizontalrule |
null |
在插入字符处插入一个<hr> 元素 |
insertimage |
图像的URL
|
在插入字符处插入一个图像 |
insertorderedlist |
null |
在插入字符处插入一个<ol> 元素 |
insertunorderedlist |
null |
在插入字符处插入一个<ul> 元素 |
insertparagraph |
null |
在插入字符处插入一个<p> 元素 |
italic |
null |
将选择的文本转换成斜体 |
justifycenter |
null |
将插入光标所在文本块居中对齐 |
justifyleft |
null |
将插入光标所在文本块左对齐 |
outdent |
null |
凸排文本(减少缩进) |
paste |
null |
将剪贴板中的文本粘贴到选择的文本 |
removeformat |
null |
移除插入光标所在文本块的块级格式。这是撤销formatblock 命令的操作 |
selectall |
null |
选择文档中的所有文本 |
underline |
null |
为选择的文本添加下划线 |
unlink |
null |
移除文本的链接。这是撤销createlink 命令的操作 |
可通过源码来查看具体使用场景。源码下载,14章,兼容浏览器的js在13章
// 选择文本之后 触发该js语句执行
// 转换粗体文本
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>");
// ... ...
// 同样的方法也适用于页面中contenteditable 属性为"true"的区块
// 只要把对框架的引用替换成当前窗口的document 对象即可。
//转换斜体文本
document.execCommand("italic", false, null);
queryCommandEnabled()
可以用它来检测是否可以针对当前选择的文本,或者当前插入字符所在位置执行某个命令。这个方法接收一个参数,即要检测的命令。如果当前编辑区域允许执行传入的命令,这个方法返回true
,否则返回false
。
var result = frames["richedit"].document.queryCommandEnabled("bold");
// 如果能够对当前选择的文本执行"bold"命令,以上代码会返回true。
// 需要注意的是返回true,并不意味着实际上就可以执行相应命令,
// 而只能说明对当前选择的文本执行相应命令是否合适。
// 例如,Firefox 在默认情况下会禁用剪切操作,但执行queryCommandEnabled("cut")也可能会返回true
queryCommandState()
用于确定是否已将指定命令应用到了选择的文本。
var isBold = frames["richedit"].document.queryCommandState("bold");
// 如果此前已经对选择的文本执行了"bold"命令,那么上面的代码会返回true。
// 一些功能全面的富文本编辑器,正是利用这个方法来更新粗体、斜体等按钮的状态的。
queryCommandValue()
用于取得执行命令时传入的值(即前面例子中传给document.execCommand()
的第三个参数)。
var fontSize = frames["richedit"].document.queryCommandValue("fontsize");
// 在对一段文本应用"fontsize"命令时如果传入了7,那么这段代码就会返回"7"
// 通过这个方法可以确定某个命令是怎样应用到选择的文本的,可以据以确定再对其应用后续命令是否合适。
富文本选区
在富文本编辑器中,使用框架(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()
:返回选区所包含的文本内容。
-
var selection = frames["richedit"].getSelection();
//取得选择的文本
var selectedText = selection.toString();
//取得代表选区的范围
var range = selection.getRangeAt(0);
//突出显示选择的文本
var span = frames["richedit"].document.createElement("span"); span.style.backgroundColor = "yellow"; range.surroundContents(span);
// IE不支持 DOM 范围 但我们可以通过它支持的 selection 对象操作选择的文本(range.text / range.htmlText)。
// IE 中的 selection 对象是 document 的属性
// 要取得富文本编辑器中选择的文本,首先必须创建一个文本范围
var range = frames["richedit"].document.selection.createRange();
range.pasteHTML("<span style=\"background-color:yellow\"> " + range.htmlText +"</span>");
以上代码会为富文本编辑器中被选择的文本添加黄色的背景。这里使用了默认选区中的 DOM
范围, 通过 surroundContents()
方法将选区添加到了带有黄色背景的<span>
元素中。IE的代码通过htmlText
取得了当前选区中的 HTML
,然后将其放在了一对<span>
标签中,最后又使用 pasteHTML()
将结果重新插入到了选区中。
表单与富文本
由于富文本编辑是使用iframe
而非表单控件实现的,因此从技术上说,富文本编辑器并不属于表单。富文本编辑器中的HTML
不会被自动提交给服务器,而需要我们手工来提取并提交 HTML
。通常可以添加一个隐藏的表单字段,让它的值等于从 iframe
中提取出的 HTML
,来说,在提交表单之前,从 iframe
中提取出 HTML
,并将其插入到隐藏的字段中。下面就是通过表单的onsubmit
事件处理程序实现上述操作的代码。
form.addEventListener('submit',function(e){
e.target.element["comments"].value = frames["richedit"].document.body.innerHTML;
})
取得了 iframe
中的 HTML
,然后将其插入到了名为 "comments"
的表单字段中。这样可以确保恰好在提交表单之前填充"comments"
字段。对于contenteditable
元素可以使用document.getElementById("rechedit").innerHTML
来获取到HTML
富文本编辑功能是通过一个包含空 HTML
文档的iframe
元素来实现的。通过将空文档的 designMode
属性设置为"on"
,就可以将该页面转换为可编辑状态,此时其表现如同字处理软件。另外, 也可以将某个元素设置为 contenteditable
。在默认情况下,可以将字体加粗或者将文本转换为斜体, 还可以使用剪贴板。avaScript
通过使用 execCommand()
方法也可以实现相同的一些功能。另外,使用queryCommandEnabled()
、queryCommandState()
和 queryCommandValue()
方法则可以取得有关 文本选区的信息。由于以这种方式构建的富文本编辑器并不是一个表单字段,因此在将其内容提交给服务器之前,必须将iframe
或 contenteditable
元素中的 HTML
(富文本编辑中的html必然是一段文本字符串) 复制到一个表单字段中。