表单脚本
表单基础
Web表单在HTML中以form元素表示,在js中以HTMLFormElement类型表示
HTMLFormElement类型继承自HTMLElement,但是它有自己的属性和方法:
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属性
可以通过document.forms获取页面上所有的表单元素,然后使用表单名来访问:
let forms = document.forms;forms[0];forms["form1"];
提交表单
提交表单可以通过type属性为submit的input或button来定义,也可以通过type属性为image的input元素定义
有提交按钮的表单在其控件取得焦点时(textarea除外),回车也能触发提交表单
通过js的form.submit()方法提交表单不会触发submit事件
为了防止用户多次提交表单,可以在用户点击之后禁用按钮或者通过onsubmit事件处理程序取消之后的表单提交
重置表单
通过type属性为reset的input或button,用户可以重置表单
通过js的form.reset()方法重置表单会触发reset事件
表单字段
所有表单元素都是表单elements属性中包含的一个值,这个elements集合是一个有序列表
所有的input、textarea、button、select、fieldset元素都被包含在elements集合中,可以通过索引和name访问
let form = document.getElementById('form');form[0];form['input'];form.length;form.input;
同name元素会作为一个集合返回
1、表单字段的公共属性
除fieldset元素外,所有的表单字段都有一组相同的属性:
disabled:布尔值,表示表单字段是否禁用
form:指针,指向表单字段所属的表单,只读
name:字符串,这个字段的名字
readOnly:布尔值,表示这个字段是否只读
tabIndex:数值,表示这个字段在按Tab键时的切换顺序
type:字符串,表示字段类型
value:要提交给服务器的字段值,对文件输入来说这个字段是只读的,仅包含路径
type属性的特殊值:
单选列表(<select></select>
):select-one、多选列表(<select multiple></select>
):select-multiple
对于input和button元素,可以动态修改type属性,但是select元素的type属性是只读的
2、表单字段的公共方法
每个表单字段都有两个公共方法:focus()和blur()
focus():
焦点在表单字段上时,该字段可以响应键盘事件
但是如果调用focus的字段type为hidden,或者该字段被CSS属性display或visibility隐藏了,则会出错
HTML5为表单字段增加了autofocus属性,支持的浏览器会自动为带有该属性的元素设置焦点,而无需使用js
可以在使用前检测表单是否设置了autofocus属性,以及排除不支持的浏览器(不支持的浏览器返回空字符串),如果表单有这个属性则返回true
通过将tabIndex属性设置为-1在调用focus(),也可以给任意元素设置焦点,只有Opera不支持
blur():
移除元素上的焦点
这两个方法都会触发focus和blur事件
3、表单字段的公共事件
所有字段还支持以下三个事件:
blur:字段失去焦点时触发
change:在input和textarea元素的value变化且失去焦点时触发,或者在select元素中选项发生变化时触发
focus:字段获得焦点时触发
文本框编程
单行input元素、多行textarea元素
input元素省略type会以text作为默认值,size指定文本框宽度(这个宽度是以字符数计量的),value指定文本框的初始值,maxLength属性用于指定文本框允许的最多字符数
textarea元素总是会创建多行文本框,rows属性指定这个文本框的高度(以字符数计量),以cols属性指定文本框宽度(以字符数计量),textarea初始值必须包含在元素之间;textarea不能在HTML中指定最大允许字符数;两种类型的文本框内容都在value中
应该使用value属性而不是DOM方式读写文本框的值,对value属性的修改也不会总体现在DOM中
选择文本
两个文本框都支持select()方法,用于选中全部文本框中的文本;大部分浏览器会在调用select()方法后自动将焦点设置到文本框外(Opera例外)
1、select事件
选中文本框和使用select()方法都会触发select事件
2、取得选中的文本
HTML扩展了文本框属性:selectionStart、selectionEnd
这两个属性分别表示被选择文本的起点和终点,例如
function getSelectedText(textBox) { return textBox.value.substring(textBox.selectionStart, textBox.selectionEnd);}
IE8以及更早版本不支持这两个属性,详情查看红宝书p589
3、部分选中文本
调用setSelectionRange()方法可以选中部分文本,该方法接收两个参数:开始和停止字符的索引值(与substring()方法一样)
如果想看到选择,则需要在调用该方法之前或之后给文本框设置焦点
IE8及更早版本方法不同,请查看红宝书p590
输入过滤
输入框中有些字符是我们需要屏蔽的,所以我们必须通过js来进行输入过滤
1、屏蔽字符
textbox.addEventListener('keypress', (event) => { if (判断条件) { event.preventDefault(); }})
判断条件自己决定,符合条件的按键都会被阻止输入;为了防止某些按键被错误屏蔽,相关浏览器还有一些不同规则,查看红宝书p591
2、处理剪贴板
HTML5增加了剪贴板事件,以下是与剪贴板相关的6个事件:
beforecopy:赋值操作发生前触发
copy:复制发生时触发
beforecut:剪切操作发生前触发
cut:剪切操作发生时触发
beforepaste:粘贴操作发生前触发
paste:粘贴操作发生时触发
三个前置事件可以对后续操作数据进行更改,但是取消这三个事件不能取消剪贴板操作,必须取消真正的copy、cut、paste事件
剪贴板上的数据可以通过window(IE)或event(Firefox、Safari、Chrome)上的clipboardData对象来获取;在除IE以外的三家浏览器上,为了防止未经授权的访问,这个对象只能在剪贴板事件期间访问,而IE在任何时候都能访问
clipboardData对象上有三个方法:getData()、setData()、clearData()
getData()接受一个参数,这个参数时要检索的数据的格式:IE规定了两个类型“text”或“URL”,不过其它三家浏览器期待MIME类型,不过会将“text”视为等价于“text/plain”
setData()也类似,第一个参数指定数据类型,第二个参数为要保存的文本;IE规定了“text”和“URL”,其它三家浏览器期待MIME类型,不过这次不支持“text”(这个方法只有IE支持)
自动切换
当满足了当前文本框输入条件后,自动将焦点跳转到下一个文本框
HTML5约束验证API
可以使用HTML标记指定对特定字段的约束,然后浏览器会自动根据这些约束执行表单验证
1、必填字段
第一个条件是给表单字段添加require属性;任何带有require属性的字段都必须有值,否则无法提交表单,这个属性适用于input、textarea、select(Opera知道版本11都不支持select的require属性),可以通过js检测对应元素的require属性来判断表单字段是否为必填:
let isFill = document.forms[0].element['username'].required;
检测浏览器是否支持require:
let isReq = "required" in document.createElement('input');
但是Safari对必填字段啥也不做,也不会阻止表单提交
2、更多输入类型
HTML5为input新增了几个type值,例如“email”和“url”
但是指定一个特殊输入类型并不会阻止用户输入无效的值
3、数值范围
HTML5还指定了更多数值类型:number、range、datetime…
上述类型都可以指定min属性和max属性,以及step属性(从min到max的步长值)
如果只允许输入从0到100中5的倍数(根据浏览器的不同也可能会或者不会出现上下按钮)
上述属性都可以在js中通过DOM属性来访问和修改
还有两个方法:stepUp()和stepDown(),这两个参数接收一个可选参数:要从当前值加上或减去的数值(默认情况下步长为1)
4、输入模式
HTML5为文本字段新增了pattern属性,这个属性用于指定一个正则表达式,用户输入的文本必须与之匹配
但是指定一个特殊输入类型并不会阻止用户输入无效的值
5、检测有效性
使用checkValidity()方法可以检测表单中任意给定字段是否有效,所有表单元素上都可以使用,如果字段值有效就会返回true,否则返回false
判断字段是否有效的依据是前面提到的约束条件,所以必填字段如果没有值就会被无视,而字段值不匹配pattern属性也会被视为无效
要检查整个表单,直接在表单上调用checkValidity()方法,在每个字段都有效时返回true,只要有一个字段无效就返回false
checkValidity()方法只会告诉我们字段是否有效,而validity属性会告诉我们字段为什么有效或无效;这个属性是一个对象,包含返回一系列布尔值的属性:
customError:如果设置了setCustomValidity()就返回true,否则返回false
patternMismatch:如果字段值不匹配pattern属性则返回true
rangeOverflow:如果字段值大于max的值则返回true
rangeUnderflow:如果字段值小于min的值则返回true
stepMisMatch:如果字段值与min、max和step的值不符则返回true
tooLong:如果字段值的长度超过了maxlength属性指定的值则返回true;某些浏览器会自动限制字符数量,因此这个属性始终为false
typeMismatch:如果字段值不是email或url要求的格式则返回true
valid:如果所有其他的属性值都为false则返回true
valueMissing:如果字段值是必填但没有值则返回true
6、禁用验证
通过指定novalidate属性可以禁止对表单进行任何验证
这个值可以通过js属性noValidate检索或设置,设置为true表示属性存在,设置为false则相反
如果一个表单有多个提交按钮,则可以给特定的提交按钮添加formnovalidate属性,指定通过该按钮无需验证即可提交表单
选择框编程
选择框时使用select和option元素创建的,它有单独提供了以下属性:
add(newOption, relOption):在relOption之前向控件中添加新的option
multiple:布尔值,表示是否允许多选,等价于HTML的multiple属性
options:控件中所有option元素的HTMLCollection
remove(index):移除给定位置的选项
selectedIndex:选项中基于0的索引值,如果没有选中则为-1,对于多选列表始终是第一个索引值
size:选项框中可见的行数,等价于HTML的size属性
选择框的value属性:
如果没有选中项,则是空字符串
如果有一个选中项,且其value属性有值,则选择框value的值就是该值,即使选中项value为空字符串
如果有一个选中项,且value属性没有指定值,则选择框的value是选中项的文本内容
如果有多个选中项,则选择框的值根据前两条规则取得第一个选中项的值
每个option元素在DOM中都由一个HTMLOptionElement对象表示,它独有以下属性:
index:选项在options集合中的索引
label:选项的标签,等价于HTML的label属性
selected:布尔值,表示是否选中了当前项,把这个属性设置为true会选中当前项
text:选项的文本
value:选项的值(等价于HTML的value属性)
选择框会在选中一项时立即触发change事件;
js中的value属性始终等于HTML中的value属性,在HTML中没有指定value属性的情况下,IE8以及更早版本返回空字符串,IE9及之后版本、其他主流浏览器会返回与text相同的值
选项处理
对于单项选择框,使用selectedIndex属性很方便;对于多项选择框,该属性只能返回第一个选择的值
给selected属性赋true时,不会影响多项选择框,但是单项选择框会取消之前的选择(之前选择的selected属性会被移除)
添加选项
可以使用DOM方法,也可以使用Option构造函数创建新选项,这个构造函数接收两个参数:text、value,value是可选的;这个函数通常会返回Object实例,但是DOM合规的浏览器都会返回一个option元素,所以仍然可以使用appendChild()方法将选项添加到选择框
这个方法在IE8以及更低版本不能设置新选项的文本
选择框add()方法也能添加,该方法接收两个参数:要添加的新选项、要添加到其前面的参考选项;如果想在列表末尾添加选项,第二个参数应该是null
IE8及更早版本有一些不同,查阅红宝书p600
移除选项
removeChild()传入要移除的选项
选择框的remove()方法,接收一个参数,表示要移除的索引值
直接将选项设置为null,如selectbox.option[0] = null;
要清除选择框的所有项,则需要迭代所有选项并逐一移除
移动和重排选项
使用DOM方法可以很快的将选项重排,利用appendChild和insertBefore
表单序列化
随着Ajax发展,表单序列化成为一个常见需求,提交表单时要把什么发送到服务器
字段名和值是URL编码的并以和号&分隔
禁用字段不会发送
复选框和单选按钮只在被选中时才发送
类型为reset或button的按钮不会发送
多选字段的每个选中项都有一个值
通过点击按钮提交表单时,会发送该提交按钮;否则不会发送提交按钮;类型为image的input元素视同提交按钮
select元素的值是被选中option元素的value属性,如果没有value属性,则改值是他的文本
可以通过这几个来自定义一个serialize(),返回要提交的序列化后字符串
富文本编辑器
最基本的技术就是在空白HTML、
文档中嵌入一个iframe;通过designMode属性,可以将这个空白文档变成可编辑的,实际编辑的则是body元素的HTML;designMode有两个值:off(默认)和on,设置为on时,整个文档都会变成可编辑的
使用contenteditable
指定该属性的元素会立即被用户编辑,元素中包含的任何文本都会被自动编辑,元素本身类似于textarea元素
通过设置元素的contentEditable属性,可以随时切换元素的可编辑状态,该属性有三个属性值:true、false、inherit
与富文本交互
与富文本编辑器交互的主要方法是使用document.execCommand(),该方法接收三个参数:要执行的命令、表示浏览器是否为命令提供用户界面的布尔值、执行命令必须的值(不需要则为null)
为了浏览器兼容,通常第二个参数设置为false,因为true的话Firefox会报错
有一些很常用的命令,查看红宝书p604
如果是使用contenteditable属性的元素,就要使用前窗口而不是内嵌窗口的document对象
还有一些其他方法:queryCommandEnabled(),此方法用于确定对当前选中文本或光标所在位置是否能执行相关命令,它接收一个参数:检查的命令名,如果可执行返回true,否则返回false;但是返回true不代表允许执行相关命令,只不过代表当前选区适合执行这个命令
另一个方法:queryCommandState(),用于确定相关命令是否应用到了当前文本选区
最后一个方法:queryCommandValue(),返回用于执行命令时使用的值,也就是execCommand()的第三个参数
富文件选择
在内嵌窗格中使用getSelection()方法,可以获得副文本编辑器的选区;这个方法在document和window上,返回当前选中文本的Selection对象,该对象有以下属性:
anchorNode:选区开始的节点
anchorOffset:在anchorNode中,从开头开始到选区开始跳过的字符数
focusNode:选区结束的节点
focusOffset:focusNode中包含在选区内的字符数
isCollapsed:布尔值,表示选区起点和终点是否在同一个地方
rangeCount:选区中包含的DOM范围数量
它也有以下方法:
addRange(range):把给定的DOM范围添加到选区
collapse(node, offset):将选取折叠到给定节点中给定的文本偏移处
collapseToEnd():将选区折叠到终点
collapseToStart()
containsNode(node):确定给定节点是否包含在选区中
deleteFromDocument():从文档中删除选区文本
extends(node, offset):通过将focusNode和focusOffset移动到指定值来扩展选区
getRangeAt(index):返回选区中指定索引处的DOM范围
removeAllRange():从选区中移除所有DOM范围
removeRange(range):从选区中移除指定的DOM范围
selectAllChildren(node):清除选区并选择给定节点的所有子节点
toString():返回选文中的文本内容
surroundContents()方法可以给选中文本添加标签
通过表单提交富文本
将富文本内容更新到表单中的承载元素上,可以间接实现富文本的表单提交