Skip to content

表单脚本

表单基础

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 获取页面上所有的表单元素,然后使用表单名来访问:

javascript
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 访问

javascript
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

这两个属性分别表示被选择文本的起点和终点,例如

javascript
function getSelectedText(textBox) {
  return textBox.value.substring(textBox.selectionStart, textBox.selectionEnd);
}

IE8 以及更早版本不支持这两个属性,详情查看红宝书 p589

3、部分选中文本

调用 setSelectionRange()方法可以选中部分文本,该方法接收两个参数:开始和停止字符的索引值(与 substring()方法一样)

如果想看到选择,则需要在调用该方法之前或之后给文本框设置焦点

IE8 及更早版本方法不同,请查看红宝书 p590

输入过滤

输入框中有些字符是我们需要屏蔽的,所以我们必须通过 js 来进行输入过滤

1、屏蔽字符
javascript
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 属性来判断表单字段是否为必填:

javascript
let isFill = document.forms[0].element["username"].required;

检测浏览器是否支持 require:

javascript
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()方法可以给选中文本添加标签

通过表单提交富文本

将富文本内容更新到表单中的承载元素上,可以间接实现富文本的表单提交