本章主要介绍:表单、文本框验证与交互、使用其他表单控制。这一章会继续沿用上一章 封装的 EventUtil 对象(具体参考前面的
事件)
JavaScript最初的一个应用,就是分担服务器处理表单的责任,打破处处依赖服务器的局面
一、表单的基础知识
JavaScript中,表单对应的是 HTMLFormElement 类型。HTMLFormElement 继承了 HTMLElement。HTMLFormElement 有自己下列独有的属性和方法
- acceptCharset:服务器能够处理的字符集:等价于HTML中的 accpet-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>元素 引用的方式有好几种:最常见的方式是 使用 getElementById() 方法找到它
var form = document.getElementById('myForm')
其次,通过document.forms 获取页面中所有的表单,再通过 索引 或 name值 来访问
var firstForm = document.forms[0] // 获取页面中的第一个表单
var myForm = document.forms['form2'] // 获取页面中 名称为 “form2” 的表单
在较早的浏览器或者那些支持向后兼容的浏览器中,也会把每个设置了 name 特性的 表单作为属性保存在 document 对象中。通过document.form2 可以访问到名为 "form2" 的表单。
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" />
以这种方式提交表单时,浏览器会在将请求发送给服务器之前触发 submit 事件。这样,我们就有机会验证表单数据,并决定是否允许提交表单。
var form = document.getElementById('myForm')
EventUtil.addHandler(form, 'submit', function(event){
// 取得事件对象
event = EventUtil.getEvent(event)
// if () {
// 阻止默认事件
EventUtil.preventDefault(event)
// }
})
在JavaScript中,以编程方式调用 submit() 方法也可以提交表单。这种方式无需表单包含提交按钮。任何时候都可以正常提交表单。
var from = document.getElementById('myForm')
// 提交表单
form.submit()
调用 submit() 方法提交表单的形式,不会触发 submit事件,因此要记得在调用此方法之前先验证表单数据。
提交表单时可能出现的最大问题,就是重复提交表单。为此,可以在在第一次提交表单后就禁用提交按钮,或者利用 onsubmit 事件处理程序取消后续的表单提交操作。
1.2、重置表单
使用 type 特性值为 “reset”的 <input> 或 <button> 都可以创建重置按钮,
<!-- 通用重置按钮 -->
<input type="reset" value="Reset Form">
<!-- 自定义重置按钮 -->
<button type="reset">Reset From</button>
也可以使用 JavaScript 的方式 来重置表单
var form = document.getElementById('myForm')
// 重置表单
from.reset()
用户单击重置按钮重置表单时,会触发 reset 事件。我们可以在必要时取消重置操作
/* 阻止重置表单操作 */
var form = document.getElementById('myForn')
form.onreset = function(event) {
event.preventDefault()
}
1.3、表单字段
每个表单都有一个 elements 属性,该属性是表单中所有表单元素(字段)的集合。可以按照位置和 name 特性来访问它们,
var form = document.getElementById('myForm')
// 取得表单中的第一个字段
var field1 = form.elements[0]
// 取得表单中name 为 textbox1的字段
var field2 = form.elements['textbox1']
// 取得表单中包含的字段的数量
var fieldCount = from.elements.length
如果使用 name 实现访问元素时,多个表单控件的 name 相同,就会返回一个 以改name 命名的 NodeList,然后可以通过 索引 访问这个集合中的元素
如下
<input type="radio" name="color" value="red"> red
<input type="radio" name="color" value="cyan"> cyan
<input type="radio" name="color" value="violet"> violet
<script>
var colors = document.forms[0]['color']
console.log(Object.prototype.toString.call(colors))
console.log(colors[0]) // 第一个 单选框
</script>
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"
避免多次提交,最常见的解决方案,就是在第一次单机后就禁用提交按钮。
// 避免多次提交表单
EventUtil.addHandler(form, 'submit', function(event) {
event = EventUtil.getEvent(event)
var target = EventUtil.getTarget(event)
// 取得提交按钮
var btn = target.elements['submit-btn']
// 禁用它
btn.disabled = true
})
注意不能通过 onclick 事件处理程序来实现这个功能,原因是不同浏览器之间存在”时差“:有点浏览器会在触发表单的 submit 事件之前触发 click 事件,意味着会在提交发生之间禁用按钮,结果永远都不会提交表单
除了 <fieldset> 之外,所有表单字段都有 type 属性。对于 <input> 元素,这个值等于 HTML 特性 type 的值。对于其他元素,这个 type 属性的值如下表所列:
说明 | HTML示例 | type 属性的值 |
---|---|---|
单选列表 | <select>...</select> | "select-one" |
多选列表 | <select multiple>...</select> | "select-multiple" |
自定义按钮 | <button>...</button> | "submit" |
自定义非提交按钮 | <button type="button">...</button> | "button" |
自定义重置按钮 | <button type="reset">...</button> | "reset" |
自定义提交按钮 | <button type="submit">...</button> | "submit |
<input> 和 <button> 元素的 type 属性是可以动态修改的,而 <select> 元素的 type 属性则是只读的。
1.3.2、共有的表单字段方法
每个表单字段都有两个方法:focus() 和 blur()。
focus() 方法用于将浏览器的焦点设置到表单字段,级激活表单字段,使其可以响应键盘事件。为此,可以侦听页面的 load 事件,并在该事件发生时在表单的第一个字段上调用 focus() 方法,如下:
EventUtil.addHandler(window, 'load' , function(event) {
document.forms[0],elements[0].focus()
})
需要注意的是:如果 focus() 方法的对象是一个 type="hidden" 的 <input> 元素的话,那么以上代码会导致错误。另外,如果使用 CSS 的 display 和 visibility 属性隐藏了该字段,同样也会导致错误
HTML5 为表单字段新增了一个 autofocus 属性。在支持这个属性的浏览器中,只要设置这个属性不用 JavaScript就能自动把焦点移动到相应字段。例如:
<input type="text" autofocus />
可以通过 autofocus 属性获取 元素上面的 autofocus 的状态,在支持的浏览器中如果设置了为true
blur() 作用是从元素上移走焦点
document.forms[0].elements[0].blur()
1.3.3、共有的表单字段事件
所有的表单字段都支持下列三个事件
- blur:当前字段市区焦点时触发
- change:对于<input> 和 <textarea> 元素,它们失去焦点且 value 值改变时触发;对于 <select> 元素,在其选项改变时触发
- focus:当前字段获得焦点时触发
change 事件经曾用于验证用户在字段中输入的数据。
下面例子中,对上诉三个事件简单使用
var textbox = document.forms[0].elements[0]
EventUtil.addHandler(textbox, "focus", function(event) { // 获得焦点时 编程黄色
event = EventUtil.getEvent(event)
var target = EventUtil.getTarget(event)
if (target.style.backgroundColor != 'red') {
target.style.backgroundColor = 'yellow'
}
})
EventUtil.addHandler(textbox, "blur", function(event) { // 失去焦点
event = EventUtil.getEvent(event)
var target = EventUtil.getTarget(event)
// 验证用户是否输入的是数字
if (/[^\d]/.test(target.value)) {
target.style.backgroundColor = 'red'
} else {
target.style.backgroundColor = ''
}
})
EventUtil.addHandler(textbox, "input", function(event) { // value 值变化时
event = EventUtil.getEvent(event)
var target = EventUtil.getTarget(event)
console.log(target.value)
// 验证用户是否输入的是数字
if (/[^\d]/.test(target.value)) {
console.log(1)
target.style.backgroundColor = 'red'
} else {
target.style.backgroundColor = ''
}
})
因为 change 事件必须 在value值改变且失去焦点才会触发,所以这里用 input 事件来实时监听
二、文本框脚本
在 HTML 中,有两种方式来表现文本框,<input> 、<textarea> 两种元素
<input>
- 通过设置 size 特性,可以指定文本框中能够显示的字符数
- 通过value特性,可以设置文本框的初始值
- 通过maxlength特性则用于指定文本框 可以接受的最大字符数
<textarea>
- rows特性指定文本框的字符行数
- cols 特性指定文本框的字符列数
与 <Input> 元素不同,<textarea>的初始值必须要放在 <textarea></textarea>之间
<textarea rows="25" cols="5"> initial value </textarea>
值得注意的时:在操作 value 属性时,不建议使用 标准的 DOM 方法(setAttribute()),这样对 value 属性所作的修改,不一定会反映在 DOM 中
2.1、选择文本
上诉两种文本框都支持 select() 方法,这个方法用于选择文本框中的所有文本。在调用 select() 方法时,大多数浏览器都会将焦点设置到 文本框中
var textbox = document.forms[0].elements["textarea"]
textbox.select()
在文本框获得焦点时选择其所有文本,这是一种非常常见的做法,特别是在 文本框包含默认值的时候。因为这样做可以让用户不必一个一个地删除文本。
EventUtil.addHandler(textbox, "focus", function(event) {
event = EventUtil.getEvent(event)
var target = EventUtil.getTarget(event)
target.select()
})
2.1.1、select 事件
与 select() 方法对应的,有一个 select 事件,在选择了文本框的文本是,就会触发select事件,而在IE8及更早版本中,只要用户选择了一个字母(不必释放鼠标),就会触发select 事件。另外,在调用 select() 方法时也会触发 select 事件。
var textbox = document.forms[0].elements['textbox1']
EventUtil.addHandler(textbox, "select", function(event) {
console.log("select text")
})
当用户选择 textbox 中的文本时,就会触发这个事件 ,输出 select text
2.1.2、取得选择的文本
通过 select 事件我们可以知道用户什么时候选择了文本,但任然不知道用户选择了什么文本。 HTML5 通过了一些 扩展方案解决了这个问题。添加了两个属性:selectionStart 和 selectionEnd。 这两个属性中保存的是基于 0 的数值,表示所选择文本的范围(即文本选区开头和结尾的偏移量)。
function getSelectedText(textbox) {
return textbox.value.substring(textbox.selectionStart, textbox.selectionEnd)
}
// 获取选区的文本
var textbox = document.forms[0].elements["textarea"]
EventUtil.addHandler(textbox, "select", function(event) {
// 调用方法
console.log("select Text :" + getSelectedText(textbox))
})
IE8及之前不支持这两个属性而是提供了另一种方案
IE8及更早的版本中有一个 document.selection 对象,其中保存着用户在整个文档范围内选择的文本信息,与 select 事件一起使用的时候,可以假定是用户选择了文本框中的文本。要取得选择的文本,首先必须创建一个范围,然后再将文本从其中提取出来。
function getSelectedText(textbox) {
if (typeof textbox.selectionstart === 'number') {
return textbox.value.substring(textbox.selectionStart, textbox.selectionEnd)
} else if(document.selection) { // 针对 IE
return document.selection.createRange().text
}
}
2.1.3、选择部分文本
HTML5 也为选择文本框中的部分文本提供了解决方案,所有文本款都有一个 setSelectionRange() 方法,这个方法接收两个参数:要选择的第一个字符的索引、选择的最后一个字符之后的字符的索引
var textbox = document.forms[0].elements["textarea"]
textbox.value = 'Hello World!'
textbox.select() // 使当前 获取焦点
// 选择所有文本
textbox.setSelectionRange(0, textbox.value.length)
// 选择前3个字符
textbox.setSelectionRange(0, 3)
// 选择第 4-6 个字符
textbox.setSelectionRange(4, 7)
要看到选择的文本,必须在调用 setSelectionRange() 之前或之后立即将焦点设置到文本框
IE8及更早版本,要选择文本框中的部分文本,
- 首先使用 IE 在所有文本框是 提供的 createTextRange() 方法创建一个范围,
- 然后 使用 moveStart() 和 moveEnd() 这两个范围方法将范围移动到位
- 在调用这两个方法之前,还必须使用 collapse() 将范围折叠到文本框的开始位置
- 使用 范围的 select() 方法选择文本
var textbox = document.forms[0].elements["textarea"]
textbox.value = 'Hello World!'
var range = textbox.createTextRange()
// 选择所有文本
range.collapse(true)
range.moveStart('character', 0)
range.moveEnd('character', textbox.value.length)
range.select()
// 选择前3个字符
range.collapse(true)
range.moveStart('character', 0)
range.moveEnd('character', 3)
range.select()
实现跨浏览器编程,结合上诉两种方案组合
function selectText(textbox, startIndex, endIndex) {
if (textbox.setSelectionRange) {
textbox.setSelectionRange(startIndex, endIndex)
} else if(textbox.createTextRange) { // IE
var range = textbox.createTextRange() // 创建范围
range.collapse(true) // 折叠范围
// 移动范围
range.moveStart('character', startIndex)
range.moveEnd('character', endIndex)
range.select() // 选择文本
}
// 获取焦点
textbox.focus()
}
可以像下面这样使用这个方法
var textbox = document.forms[0].elements['textarea']
textbox.value = 'Hello World'
// 选择所有文本
selectText(textbox, 0, textbox.value.length)
2.2、过滤输入
我们经常会要求用户在文本框中输入特定的数据,或者输入特定格式的数据。综合运用事件和DOM手段,可以将普通的文本框转换成能够理解用户输入数据的功能型控件。
2.2.1、屏蔽字段
响应向文本框中插入字符操作的是 keypress 事件。因此,可以通过阻止这个事件的默认行为来屏蔽此类字符。
EventUtil.addHandler(textbox, 'keypress', function(event) {
event = EventUtil.getEvent(event)
EventUtil.preventDefault(event)
})
如果只想屏蔽特定字符,则需要检测 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)))) { // 获取键码对应字符在进行正则检测 取反
EventUtil.preventDefault(event)
}
})
仅考虑屏蔽不是数值的字符还不够,还要避免屏蔽一些极为常用和必要的键。所幸的是,要检测这些键并不困难。
在Firefox中,所有由非字符键触发的 keypress 事件对应的字符编码为0
在 Safari 以前的版本中,对应的字符编码全部为8
为了让代码更通用,只要不屏蔽那些字符编码小于10的键即可
// ...
if (!(/\d/.test(String.fromCharCode(charCode))) && charCode > 9) {
EventUtil.preventDefault(event)
}
除此之外还有一个文本需要处理:复制、粘贴及其他操作还有用到 Ctrl 键。在除IE之外的所有浏览器中,前面的代码也会屏蔽 Ctrl + C、Ctrl + V,以及其他使用 Ctrl 的组合键。因此最后还要添加一个检测条件,以确保用户没有按下啊 Ctrl 键。
if (! (/\d/.test(String.fromCharCode(charCode))) && charCode > 9 && !event.ctrlKey) {
EventUtil.preventDefault(event)
}
2.2.2、操作剪贴板
IE 是第一个支持与剪贴板有关事件,以及通过 JavaScript 访问剪贴板数据的浏览器, HTML5后来也把剪贴板事件纳入了规范
- beforecopy:在发生复制操作当前触发。
- copy:在发生复制操作时触发
- beforecut:在发生剪切操作前触发
- cut:在发生剪切操作时触发
- beforepaste:在发生粘贴操作前触发
- paste:在发生粘贴操作时触发
由于没有针对剪贴板操作的标准,这些事件及相关对象会因浏览器而异。在Safari、Chrome 和 Firefox中,
beforecopy、beforecut、beforepaste 事件只会在显示在针对文本框的上下文菜单(预期发生剪贴板事件)的情况下触发。
但是,IE则会在触发 copy、cut和paste事件之前先触发这些事件
。至于 copy、cut和paste事件,只要是在上下文菜单中选择了相应选项,或者使用了相应的键盘组合键,所有浏览器都会触发它们。
在实际的事件发生之前
,通过 beforecopy、beforecut、beforepaste事件可以在像剪贴板发送数据,或者从剪贴板取得数据之前修改数据。不过,取消这些事件并不会取消对剪切板的操作——只有取消 copy、cut、paste 事件,才能阻止响应操作发生。
要访问剪贴板中的数据,可以使用 clipboardData 对象:在IE中,这个对象是 window 对象的 属性
;而在 Firefox 4+、Safari 和 Chrome 中,这个对象是相应 event 对象的属性
。但是,在Firefox、Safari、Chrome 中,只有在处理剪贴板事件期间,clipboardData对象才有效,这是为了防止对剪贴板的未授权访问
;在IE中,则可以随时访问 clipboardData 对象。为了确保跨浏览器兼容,最好只在发生剪贴板事件期间使用这个对象。
clipboardData 对象有三个方法
-
getDate() 用于从剪贴板中获取数据,
- 接受一个参数,即要取得的数据格式,
在IE中,有两种数据格式:“text”、“URL”
在Firefox、Safari、Chrome中,这个参数是一种MIME类型,可以使用“text”代表“text/plain”
- 接受一个参数,即要取得的数据格式,
-
setData() 设置数据
- 数据类型
IE支持:text、URL
而 Safaru 和 Chrome 只支持 MIME 类型,不能代替 - 放在剪贴板中的文本。
- 数据类型
clearData():清除数据
在成功将文本放到剪贴板中后,都会返回true;否则返回false
为了弥补这些差异,我们可以项 EventUtil 中再添加下列方法:
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)
}
}
在需要确保粘贴到文本框中的文本中包含某些字符,或者符合某种格式要求时,能够访问剪贴板是非常有用的。在paste事件中,可以确定剪贴板中的事件是否有效
EventUtil.addHandler(textbox, 'paste', function(event) {
event = EventUtil.getEvent(event)
var text = EventUtil.getClipboardText(event)
console.log(1)
if (!/^\d*$/.test(text)) {
EventUtil.preventDefault(event)
}
})
如上代码只会在,粘贴板中文本内容只包含数字的时候,才能粘贴
由于并非所有浏览器都支持访问剪贴板,所以更简单的做法是屏蔽一或多个剪贴板操作
2.3、自动切换焦点
使用 JavaScript 可以从多个方面增强表单字段的易用性。其中,最常用的一种方式就是在用户填写完当前字段时,自动将焦点切换到下一个字段。
例如,美国的电话号码通常分为三个部分:区号、局号、另外4位数字。为取得完整的电话号码,很多网页中都会提供下列3个文本框,如下DOM结构
<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 tabForward(event) {
event = EventUtil.getEvent(event)
var target = EventUtil.getTarget(event) // 获取当前DOM元素
if (target.value.length == target.maxLength) { // 如果 输入完毕(最大长度)
var form = target.form // 获取 当前字段的 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)
不过请记住,这些代码只适用于前面给出的标记,没有考虑隐藏字段
2.4、HTML5约束验证API
为了在将表单提交到服务器之前验证数据,HTML5新增了一些功能。有了这些功能,几遍JavaScript被禁用或者由于种种原因未能加载,也可以确保基本的验证
2.4.1、必填字段
required 属性
<input type="text" name="username" required />
在JavaScript中,通过对应的required 属性,可以检查某个表单字段是否为必填字段
var isUsernameRequired = document.forms[0].elements["username"].required
另外,使用下面这行代码可以测试浏览器是否支持required属性
var isRequiredSupported = "required" in document.createElement("input")
对于空着的必填字段,不同浏览器有不同的处理方式。Firefox4和Opera11会阻止表单提交并在相应字段下发弹出帮助框,而Safari5-、Chrome9-则什么也不做,而且也不会阻止表单提交。现在的浏览器以便都会阻止提交
2.4.2、其他输入类型
HTML5 为<input> 元素的 type 属性又增加了几个值。“email”、“url”是两个得到支持最多的类型,各浏览器也都给他们增加了定制的验证机制。
<input type="email" name="email" />
<input type="url" name="homepage" />
"email" 类型要求输入的文本必须符合电子邮件地址的模式,而"url"类型要求输入的文本必须符合 URL 模式。
要检查浏览器是否支持这些类型,可以在 JavaScript中创建一个 <input>元素的type设置为其中一个,再检测这个属性的值
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(两个刻度之间的差值)。想让用户只能输入0到100的值,而且这个值必须是5的倍数,可以这些代码:
<input type="number" min="0" max="100" step="5" name="count" />
在不同的浏览器中,可能会也可能不会看到能够自动递增和递减的数值调节按钮(向上和向下按钮)
2.4.4、输入模式
HTML5 为文本字段新增了 pattern 属性。这个属性的值是一个正则表达式,用于匹配文本框中的值。
例如:只允许在文本空中输入数值
<input type="text" pattern="\d+" name="count" />
注意,模式的开头和末尾不用加 ^ 和 $符号(假定已经有了)。这两个符号表示输入的值必须从头到尾与模式匹配。
与其他输入类型相似,指定 pattern 也不能阻止用户输入无效的文本。这个模式应用给值,浏览器来判断值是有效,还是无效。
在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() 方法。如果所有表单字段都有效,这个方法返回 true;即使有一个字段无效,这个方法也返回false
if (document.form[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。有的浏览器(如Firefox4)会自动约束字符数量,因此这个值可能永远返回 false
- typeMismatch:如果值不是"mail" 或 "url" 要求的格式,返回 true
- valid:如果这里的其他属性都是false,返回true。cjeckValidity() 也要求相同的值。
- valueMissing:如果标注为 required 的字段中没有值,则返回 true。
因此,要想得到更具体的信息,就应该使用 validity 属性来检测表单的有效性。
if (input.validity.valueMissing) {
alert('please specify a value')
} else if (inout.validity.typeMismatch) {
alert('please enter an email address.')
} else {
alert('value is invalid')
}
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="signup.php">
<input type="submit" value="submit" />
<input type="submit" value="Non-validating Submit" formnovalidate />
</form>
三、选择框脚本
选择框是通过<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-mutiple",这取决于 HTML中有没有 multiple 特性。选择框的 value 属性由当前选中项决定,相应规则如下:
- 如果没有选中的项,则选择框的 value 属性保存空字符串
- 如果有一个选中项,而且该项的 value 特性已经在 HTML 中指定,则选择框的 value 属性等于选中项的 value 特定。即使 value 特性的值是空字符串,也同样遵循此条规则
- 如果有一个选中项,但该项的 value 特性在HTML 中未指定,则选择框的 value 属性等于该项的文本
- 如果有多个选中项,则选择框的 value 属性将依据前两条规则取得第一个选中项的值。
<select name="locaation" id="selLocation">
<option value="Sunnyvale, CA">Sunnyvale</option>
<option value="">Chine</option>
<option>Australia</option>
</select>
如上DOM结构:
- 如果用户选中了第一项那么值就是 Sunnyvale, CA
- 如果用户选中了第二项,则选择框的值是 空字符串
- 如果选中第三个,则选择框的值是 Austraila
在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
选择框的 change 事件 与其他表单字段的 change 事件触发的条件不一样。其他表单字段的 change 事件是在值被修改且焦点离开当前字段时触发,而选择宽的 change 事件只要选中了选项就会触发。
3.1、选择选项
对于只允许选择一项的选择框,访问选中项的最简单方式,就是使用选择框的 selectedIndex 属性,
var selectedOption = selectbox.options[selectbox.selectedIndex]
获取后可以像下面这样显示该选项的信息
var selectbox = document.forms[0].elements[0]
var selectedIndex = selectbox.selectedIndex
var selectedOption = selectbox.options[selectedIndex]
var selectedValue = selectedOption.value
对于 可以选择多项的选择框,selectedIndex 属性就好像只允许选择一项一样。设置selectedIndex 会导致取消以前的所有选项并选择指定的那一项,而读取 selectedIndex 则只会返回选择第一项的索引值。
另一种选择选项的方式,就是去的对某一项的引用,然后将其 selected 属性设置为 true。
selectbox.options[0].selected = true
设置选项的selected 属性,不会取消对其他选中项的选择,因而可以动态选中任意多个项。需要注意的是,将selected 属性设置为 false对单选选择框没有影响
实际上,selected属性的作用主要是确定用户选择了选择框中的哪一项。要取得所有选中项,可以循环遍历选项集合,然后测试每个选项的selected 属性
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) {
return.push(option)
}
}
return result;
}
下面是使用getSelectedOptions() 函数取得选中项的实例。
var selectbox = document.getElementById('selLocation')
var selectedOptions = getSelectedOptions(selectbox)
var message = ''
for(var i = 0, len = selectedOptions.length; i < len; i++) {
message += 'selectedIndex:' + selectedOptions[i].index + '\nSelected value:' + selectedOptions[i].value
}
console.log(message)
3.2、添加选项
可以使用 JavaScript 动态创建选项,并将它们添加到选择框中。
第一种方式就是使用如下所示的DOM方法
var newOption = document.createElement('option')
newOption.appendChild(document.createTextNode('option tex'))
newOption.setAttribute('value', 'option value')
selectbox.appendChild(newOption)
第二种方式是使用 Option 构造函数来创建新选项,构造函数接受两个参数:文本(text)、值(value)
var newOption = new Option('Option text', 'Option value')
selectbox.appendChild(newOption) // 在 IE8 及指甲钳版本中有问题
第三种方式是使用 选择框的 add() 方法,接受两个参数:要添加的新选项、将位于新选项之后的选项。如果想在最后添加一个选项,第二个参数设置为 null;在IE对 add() 方法的实现中,第二个参数是可选的,如果指定,该参数必须是新选项之后的选项的索引。兼容DOM的浏要求必须指定第二个参数,因此如果要编写跨浏览器代码,需要为第二个参数传入 undefined,即可。
var newOption = new Option('option text', 'option value')
selectbox.add(newOPtion, undefined) // 最佳方案
3.3、移除选项
与添加选项类似,移除选项的方式也有很多种
- 使用 removeChild() 的方法
selectbox.removeChild(selectbox,options[0]) // 移除第一个选项
- 使用选择框的 remove() 方法。这个方法接受一个参数,即要移除选项的索引
selectbox.remove(0) // 移除第一个选项
- 将相应选项设置为 null。(这种方式也是 DOM 之前浏览器的遗留机制)
selectbox.options[0] = null // 移除第一个选项
要移除选择框中所有的项,可以迭代所有选项并移除它们
function clearSelectbox(selectbox) {
for (var i = 0, len = selectbox.options.length; i < len; i++) {
selectbox.remove(0)
}
}
3.4、移动和重排选项
在DOM标准出现之前,将一个选择框中的选项移动到另一个选择框中是非常麻烦的。使用DOM的appendChild() 方法,就可以将第一个选择框中的选项直接移动到第二个选择框中。如果为 appendChild() 方法传入一个文档中已有的元素,那么就会先从该元素的父节点中移除它,再把它添加到指定的位置。
var selectbox1 = document.getElementById('selLocations1')
var selectbox2 = document.getElementById('selLocations2')
selectbox2.appendChild(selectbox1.options[0])
移动选项与移除选项有一个共同之处,即会重置每一个选项的 index 属性
重排 选项次序的过程也十分类似,要将选择框中的某一项移动到特定位置,最合适的 DOM 方法就是 insertBefore();appendChild() 方法只适用于将选项添加到选择框的最后。
在选择框中向前移动一个选项的位置
var optionToMove = selectbox.options[1]
selectbox.insertBefore(optionToMove, selectbox.options[optionToMove.index-1]
将选择框中的选项向后移动一个位置
selectbox.insertBefore(optionToMove, selectbox.options[optionToMove.index+2])
四、序列化表单
随着 Ajax 的出现,表单序列化已经成为一种常见需求。在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) { // 如果有 name 属性 并且 有值
for (j = 0, optLen = field.options.length; j < optLen; j++) { // 遍历 所有 option
option = field.options[j]
if (option.selected) { // 如果当前选项被 选择
optValue = ''
if (option.hasAttribute) { // 如果支持 hasAttribute() 方法
optValue = (option.hasAttribute('value') ? option.value : option.text) // 查找是否存在 value 属性
} else { // 不支持 hasAttribute()
optValue = (option.attributes['value'].specified ? option.value : option.text) // 查明是否已规定 value 属性
}
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) { // 不包含没有 name 的表单字段
parts.push(encodeURIComponent(field.name) + '=' + encodeURIComponent(field.value))
}
}
}
return parts.join('&')
}
以下是这个 方法的简单使用
<form action="www.xxx.xxx" id="myForm">
地区:<select name="locaation" id="selLocation">
<option value="Sunnyvale, CA">Sunnyvale</option>
<option value="Chine">Chine</option>
<option value="Ireland">Ireland</option>
<option>Asutralia</option>
</select>
<p>用户名:<input type="text" name="username"></p>
<p>邮箱:<input type="email" name="email"></p>
<p><input type="submit" value="submit"></p>
</form>
<script>
var form = document.forms[0]
form.onsubmit = function(event) {
event.preventDefault()
var fieldsStr = serialize(form)
console.log(fieldsStr)
}
</script>
五、富文本编辑
富文本编辑,又称为 WYSIWYG(What You See Is What You Get,所见即所得)。在网页中编辑富文本内容,是人本对web应用程序最大的期待之一。这一技术的本质,就是在页面中嵌入一个包含空HTML的页面 iframe。通过设置 designMode 属性,这个空白的 HTML 页面可以被编辑,而编辑对象则是该页面 <body> 元素的 HTML 代码。designMode 属性有两个可能的值:"off"(默认值)和 "on"。在设置为 "on" 时,整个文档都会变得可以编辑
可以给 iframe 指定一个 非常简单的HTML 页面作为其内容来源。
<!DOCTYPE>
<html>
<head>
<title> Black Page for Rich Text Editing</title>
</head>
<body></body>
</html>
在包含页面中,需要使用 onload 事件处理程序来在恰当的时刻设置 designMode, 如下:
<iframe name="richedit" style="width: 100px; height: 100px;" src="./blank.html"></iframe>
<script>
window.onload = function() {
frames['richedit'].document.designMode = 'on'
}
</script>
需要注意的是,不能以文件方式在本地直接用浏览器打开的,地址栏是file:///。可以试着在本地架设服务器来调试
5.1、使用 contenteditable 属性
另一种编辑富文本内容的方式是使用名为 contenteditable 的特殊属性,这个属性也是由 IE 最早实现的。可以吧 contenteditable 属性应用给页面中的任何元素,然后用户立即就可以编辑该元素。这种方法之所以受到欢迎,是因为它不需要 iframe、空白页 和 JavaScript ,只要为元素设置 contenteditable属性即可
<div class="editable" id="richedit" contenteditable></div>
如上,元素中包含的任何文本内容就都可以编辑了,就好像这个元素变成了 <textarea> 元素一样。通过在这个元素上设置 contenteditable 元素,也能开打或关闭编辑模式
var div = document.getElementById('richedit')
div.contentEditable = true
div.contentEditable = false
contenteditable 属性有三个可能的值:"true"表示打开,"false"表示关闭,"inherit"表示从父元素那里继承
5.2、操作富文本
与富文本编辑器交互的主要方式,就是使用 document.execCommand()。这个方法可以对文档指向预定义的命令,而且可以应用大多格式。这个方法接受三个参数:
- 要执行的命令名称
- 表示浏览器是否应该为当前命令提供用户界面的一个布尔值
- 指向命令必须的一个值(如果不需要值,则传递 null)
为了确保跨浏览器的兼容性,第二个参数应该始终设置为 false,因为 Firefox 会在改参数为 true时 抛出错误
不同浏览器支持的预定义命令也不一样。下表列出了那些被支持最多的命令
命令 | 值(第三个参数) | 说明 |
---|---|---|
backcolor | 颜色字符串 | 设置文档的背景颜色 |
bold | null | 将选择的文本转换为粗体 |
copy | 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 | 将插入光标所在文本快左对齐 |
outden | null | 凸排文本(减少缩进) |
paste | null | 将剪贴板中的文本粘贴到选择的文本 |
removeformat | null | 移除插入光标所在文本块的块级格式。这是撤销 formatblock 命令的操作 |
selectall | null | 选择文档中的所有文本 |
underline | null | 为选择的文本添加下划线 |
unlink | null | 移除文本的链接。这是册小 createlink的命令的操作 |
其中,与剪贴板有关的命令在不同浏览器中的差异极大。Opera 根本没有实现任何剪贴板命令,即使不能通过 document.execCommand() 来执行这些命令,但却可以通过相应的快捷键来实现同样的操作。
使用上诉属性,来简单实现一个富文本
<button id="boldBtn">bold </button>
<button id="italicBtn">italic</button>
<button id="linkBtn">a</button>
<button id="h1Btn">H1</button>
<iframe name="richedit" style="width: 1000px; height: 300px;display: block" src="blank.html"></iframe>
<script>
window.onload = function() {
frames['richedit'].document.designMode = 'on'
document.getElementById('boldBtn').onclick = function() {
frames['richedit'].document.execCommand('bold', false, null)
}
document.getElementById('italicBtn').onclick = function() {
frames['richedit'].document.execCommand('italic', false, null)
}
document.getElementById('linkBtn').onclick = function() {
frames['richedit'].document.execCommand('createlink', false, 'http://www.baidu.com') // 默认地址,简单模拟
}
document.getElementById('h1Btn').onclick = function() {
frames['richedit'].document.execCommand('formatblock', false, '<h1>')
}
}
</script>
选区文本后,点击不同的快捷键,实现修改外观
同样的方法也适用于页面中 contenteditable 属性为 "true" 的区块,只要把对框架的引用替换成当前窗口的 document 对象即可。
<div style="width: 1000px; height: 300px;display: block;border: 1px solid violet" id="div" contenteditable>
</div>
<script>
window.onload = function() {
document.getElementById('boldBtn').onclick = function() {
document.execCommand('bold', false, null)
}
document.getElementById('italicBtn').onclick = function() {
document.execCommand('italic', false, null)
}
document.getElementById('linkBtn').onclick = function() {
document.execCommand('createlink', false, 'http://www.baidu.com') // 默认地址,简单模拟
}
document.getElementById('h1Btn').onclick = function() {
document.execCommand('formatblock', false, '<h1>')
}
}
需要注意的是,虽然所有浏览器都支持这些命令,但这些命令所产生的 HTML 仍然有很大不同。由于各个浏览器实现命令的方式不同,加上它们通过 innerHTML 实现转换的方式也不一样,因此不能指望富文本编辑器会产生一致的 HTML。
除了命令之外,还有一些于命令相关的方法
-
queryCommandEnabled()
用来检测是否可以争对当前选择的文本,或者当前插入字符所在位置执行某个命令。接受一个参数,即要检测的命令。如果当前编辑区域允许执行传入的命令,这个方法返回 true,否则返回 false。
var result = frames['richedit'].document.queryCommandEnabled('bold')
如果能够对当前选择的文本执行"bold"命令,以上代码就会返回 ture
-
queryCommandState()
方法用于确定是否已将指定命令应用到了选择的文本。
var isBold = frames['richedit'].document.queryCommandState('bold')
如果以前已经对选择的文本执行了"bold"命令,那么上面的代码会返回 ture。
-
queryCommandValue()
用于取得执行命令时传入的值(即前面例子中传给document.execCommand() 第三个参数
var fontSize = frames['richedit'].document.queryCommandValue('fontsize')
通过这个方法可以确定某个命令是怎样应用到选择的文本的,可以据以确定在对其应用后续命令是否合适
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 范围。实际上,这样会移除选区,因为选区中至少要有一个范围
- **removeRange(range):从选区中移除指定的 DOM 范围
- selectAllChildren(node):清除选区并选择指定节点的所有子节点
- toString():返回选区所包含的文本内容
Selection 对象的这些方法都极为使用,它们利用了 前面讲到的 DOM范围来管理选区。由于可以直接操作选择文本的DOM表现,因此访问DOM范围与 使用 execCommand() 相比,能够对富文本编辑器进行更加细化的控制。
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)
Firefox 3.6+ 中调用 document.getSelection() 会返回一个字符串。为此,可以在 Forefox 3.6+ 中该作调用 window.getSelection(), 从而范围 selection 对象。Firefox 8修复了这个问题
IE8 及更早的版本不支持DOM范围,但我们可以通过它支持的 selection 对象操作选择的文本。要取得富文本编辑器中选择的文本,首先必须创建一个文本范围,然后再像下面这样访问其 text 属性。
var range = frames['richedit'].document.selection.createRange()
var selectedText = range.text
虽然使用 IE 的文本范围来啊执行 HTML 操作并不像使用 DOM 范围那么可靠,但也不失为一种有效的途径。要像前面使用 DOM 范围那样实现相同的文本高亮效果,可以组合使用 **htmlText **属性和 pasteHTML() 方法
var range = frames['richedit'].document.selection.createRange()
range.pasteHTML('<span style="background-color: yellow">'+ range.htmlText + '</span>');
5.4、表单与富文本
富文本编辑器中的HTML不会被自动提交给 服务器,而需要我们手工来提交并提交HTML。为此,通常可以添加一个隐藏的表单字段,让他的值等于 从 iframe 中提取的 HTML。
form.onsubmit = function() {
this.elements['comments'].value = frames['richedit'].document.body.innerHTML
}
对于 contenteditable 元素,也可以执行类似的操作
form.onsubmit = function() {
this.elements['comments'].value = document.getElementById('richedit').innerHTML
}
六、小结
使用 JavaScript 可以增强已有的表单字段,从而创造出新的功能,或者提升表单的易用性。
- 可以使用一些标准 或 非标准的方法选择文本框的全部或部分文本
- 在文本框的内容变化时,可以通过侦听键盘事件以及检测插入的字符,来允许或禁止用户输入
- 除了Opera 其他主流浏览器都允许 通过 JavaScript 访问 剪贴板中的数据。
- IE允许在任何时候访问剪贴板的相关信息,而其他浏览器只能按在发生剪贴板事件时才能访问。
富文本编辑功能是通过一个包含空 HTML 文档的 iframe 元素
来实现。通过将空文档的 designMode 属性设置为 'on',就可以将页面转换为 可以编辑状态,此时其表现如同字处理软件。另外,也可以将某个元素设置为 contenteditable
。在默认情况下,可以将字体加粗或者将文本转换为斜体,还可以使用剪贴板。
JavaScript通过使用 execCommand() 方法也可以实现相同的一些功能。另外,使用 queryCommandEnabled()、queryCommandState()、queryCommandValue() 方法则可以取得有关文本选区的信息。由于以这种方式构建的富文本编辑器并不是一个表单字段,因此在将其内容提交给服务器之前,必须将 iframe 或 contenteditable 元素中的 HTML 复制到一个表单字段中。