JS 表单

[1] 表单对象

JavaScript最初的一个应用就是分担服务器处理表单的责任,打破处处依赖服务器的局面。尽管目前的web和JS已经有了长足的发展,但web表单的变化并不明显。由于web表单没有为许多常见任务提供现成的解决方法,很多开发人员不仅会在验证表单时使用javascript,而且还增强了一些标准表单控件的默认行为。

01. 表单属性

在HTML中,表单由form元素表示,而在javascript中,表单对应的则是HTMLFormElement类型,HTMLFormElement继承了HTMLElement,但也有自己独有的属性和方法。

acceptCharset    服务器能够处理的字符集;等价于HTML中的accept-charset特性。

action    接受请求的URL;等价于HTML中的action特性。

enctype    请求的编码类型;等价于HTML中的enctype特性。

elements    表单中所有控件的集合(HTMLCollection)。

length    表单中控件的数量。

method    要发送的HTTP请求类型,通常是"get"或"post";等价于HTML的method特性。

name    表单的名称;等价于HTML的name特性。

target    用于发送请求和接收响应的窗口名称;等价于HTML的target特性。

02. 表单事件

reset事件    将所有表单域重置为默认值

submit事件    提交表单

03. 表单方法

submit()方法

在JavaScript中,以编程方式调用submit()方法也可以提交表单。而且,这种方式无需表单包含提交按钮,任何时候都可以正常提交表单。

以调用submit()方法提交表单时,不会触发submit事件。

reset()方法

在用户单击重置按钮时,表单会被重置。使用type特性值为"reset"的<input>或<button>都可以创建重置按钮。

[注意] 元素重置时,不再触发元素上的change和input事件。

与调用submit()方法不同,调用reset()方法会像单击重置按钮一样触发reset事件。

点击外部提交按钮后,浏览器URL变成file:///C:/inetpub/wwwroot/test.html?test=1#,且没有触发onreset事件,input的value值没有变化。

点击外部重置按钮后,触发reset事件,input的value值变成2。

[2] 表单字段

表单字段又叫表单元素,表示表单所包含控件,如<input>、<select>等。

01. 访问

每个表单都有elements属性,该属性是表单中所有元素的集合。这个elements集合是一个有序列表,其中包含着表单中的所有字段,如<input>、<textarea>、<button>和<fieldset>。

[注意] 不包括图片按钮<input type="image">

每个表单字段在elements集合中的顺序,与它们出现在标记中的顺序相同,可以按照位置和name特性来访问它们。

form[name]

除了使用elements元素集合外,还可以使用form[name]来获取表单内的元素控件。

02. 属性

除了<fieldset>元素之外,所有表单字段都拥有相同的一组属性。

除了form属性之外,可以通过javascript动态修改其他任何属性。

03. 方法

每个表单字段都有两个方法:focus()和blur()。

focus()方法

focus()方法用于将浏览器的焦点设置到表单字段,即激活表单字段,使其可以响应键盘事件。

[注意] 非表单元素设置tabIndex=-1,并设置focus()方法后,也可以获得焦点。

blur()方法

与focus()方法相对的是blur()方法,它的作用是从元素中移走焦点。在调用blur()方法时,并不会把焦点转移到某个特定的元素上;仅仅是将焦点从调用这个方法的元素上面移走而已。

04. 事件

除了支持鼠标、键盘、更改和HTML事件之外,所有表单字段都支持下列3个事件:

focus

当前字段获得焦点时触发。

blur

当前字段失去焦点时触发。

change

对于<input>和<textarea>元素,在它们失去焦点且value值改变时触发;对于<select>元素,在其选项改变时触发。当然,也支持focusin和focusout事件。

顺序

当一个input元素的值改变并且失去焦点时,blur和change事件的顺序是怎么样的呢?

所有的浏览器的触发顺序都是先change事件,再blur事件。

[3] 选择文本

表单是最早用来与用户交互的工具,具有丰富的控件和属性。基本上,它们通过各种控件和属性就可以解决大部分问题。但还有一些问题还是需要表单脚本来实现的,如选择文本。

01. select()

select()方法用于选择文本框(指type为text的input元素和textarea元素)中的所有文本,该方法不接受参数,且无返回值。

02. select事件

与select()方法对应的,是一个select事件。在选择了文本框中的文本时,就会触发select事件。

不过关于什么时间触发select事件有分歧。IE8-浏览器中,只要用鼠标选择了一个字符,未释放鼠标前,就可以触发select事件;而其他浏览器中,要释放鼠标才会触发。

03. 取得选择文本

虽然通过select事件可以知道用户什么时候选择了文本,但仍然不知道用户选择了什么文本。HTML5通过一些扩展方案解决了这个问题,以便更顺利地取得选择的文本。

该规范采取的办法是添加两个属性:selectionStart和selectionEnd。这两个属性中保存的是基于0的数值,表示所选择文本的范围(即文本选区开头和结尾的偏移量)。

因为substring()方法基于字符串的偏移量执行操作,所以将selectionStart和selectionEnd直接传给它就可以取得选中的文本。

[注意] IE8-浏览器不支持。

IE8-浏览器有一个document.selection对象,其中保存着用户在整个文档范围内选择的文本信息;也就是说,无法确定用户选择的是页面中哪个部位的文本。不过,在与select事件一起使用的时候,可以假定是用户选择了文本框中的文本,因而触发了该事件。要取得选择的文本,首先必须创建一个范围,然后再将文本从其中提取出来。

04. secSelectionRange()

setSelectionRange()方法用于选择文本框中的部分文本,这个方法接收两个参数:要选择的第一个字符的索引和要选择的最后一个字符之后的字符的索引(类似于substring()方法的两个参数)。

firefox浏览器使用该方法,可以选择文本,但却没有获取焦点;而其他浏览器使用该方法可以自动获取焦点。

[注意] IE8-浏览器不支持。

IE8-浏览器支持使用范围选择部分文本。要选择文本框中的部分文本,必须首先使用createTextRange()方法创建一个范围,并将其放在恰当的位置上。然后,再使用moveStart()和moveEnd()这两个范围方法将范围移动到位。

不过,在调用这两个方法以前,还必须使用collapse()将范围折叠到文本框的开始位置。此时,moveStart()将范围的起点和终点移动到了相同的位置,只要再给moveEnd()传入要选择的字符总数即可。最后一步,就是使用范围的select()方法选择文本。

兼容

[4] 选择框脚本

选择框是通过<select>和<option>元素创建的,又称为下拉列表框。为了方便与这个控件交互,除了所有表单字段共有的属性和方法外,JavaScript还提供了一些属性和方法。

01. select

select元素用来定义一个下拉列表,包含任意数量的option和optgroup元素。select元素包含以下javascript属性:

autofocus     是否在页面加载后文本区域自动获得焦点(IE9-浏览器不支持)

disabled       是否禁用该下拉列表

form        表示文本区域所属的一个或多个表单

multiple        是否可选择多个选项

name       表示下拉列表的名称

size          表示下拉列表中可见选项的数目

options       表示所包含的options的数组

selectedOptions      表示所选择的options的数组(IE浏览器不支持)

selectedIndex         表示所选择的第一个option的索引值

以下为重要属性详解:

multiple:表示是否允许多项选择。

type

选择框的type属性有两种,一种是'select-one',表示单选;另一种是'select-multiple',表示多选。

value

选择框的value属性由当前选中项决定。

1、如果没有选中的项,则选择框的value属性保存空字符串。

2、如果有一个选中项,而且该项的value特性已经在HTML中指定,则选择框的value属性等于选中项的value特性。即使value特性的值是空字符串,也同样遵循此条规则。

3、如果有一个选中项,但该项的value特性在HTML中未指定,则选择框的value属性等于该项的文本。

4、如果有多个选中项,则选择框的value属性将依据前两条规则取得第一个选中项的值。

[注意] IE8-浏览器只支持value属性的值,不支持选择的文本值

selectedIndex

selectedIndex属性返回基于0的选中项的索引,如果没有选中项,则值为-1。对于支持多选的控件,只保存选中项中第一项的索引。

size:表示选择框的可见行数。

option:表示控件中所有的<option>元素。

02. option

在DOM中,每个<option>元素都有一个HTMLOptionElement对象表示。为便于访问数据, HTMLOptionElement对象也定义了一些属性。

[注意] IE浏览器不支持为<option>元素设置display:none。

index

index属性表示当前选项在options集合中的索引。

label

label属性表示当前选项的标签。

[注意] IE9-浏览器不支持。

selected

selected属性表示当前选项是否被选中。将这个属性设置为true可以选中当前选项。

text

text属性表示选项的文本。

value

value属性表示选项的值。

[注意] 在未指定value特性的情况下,IE8会返回空字符串;而其他浏览器返回text属性的值。

03. 添加选项

a. 添加选项可以使用DOM的appendChild()或insertBefore()方法。

b. 可以使用选择框的add()方法,add(newoption,reloption)方法向控件中插入新<option>元素,其位置在相关项(reloption)之前。使用Option构造函数来创建新选项,接受两个参数:文本(text)和值(value),第二个参数可选。

04. 移除选项

与添加选项类似,移除选项的方式也有很多种。

a. 使用DOM的removeChild()方法

b. 使用选择框的remove()方法。这个方法接受一个参数,即要移除选项的索引。

[注意] 使用该方法的好处是,若不存在被移除选项的索引,不会报错,只是静默失败。

c. 将相应选项设置为null

[注意] 该方法同样不会报错。

[5] 富文本编辑

一说起富文本,人们第一印象就是像使用word一样,在网页上操作文档。实际上差不多就是这样。富文本编辑,又称为WYSIWYG (What You See Is What You Get所见即所得),指在网页中编辑富文本内容。

01. 方式

有两种编辑富文本的方式,一种是使用iframe元素,另一种是使用contenteditable属性。

a. iframe

在页面中嵌入一个包含空HTML页面的iframe。通过设置designMode属性,这个空白的HTML页面可以被编辑,而编辑对象则是该页面<body>元素的HTML代码。

designMode属性有两个可能的值:"off"(默认值)和"on"。在设置为"on"时,整个文档都会变得可以编辑。

只有在页面完全加载之后才能设置designMode属性。因此,在包含页面中,需要使用onload事件处理程序。

[注意] 此方法必须在服务器端才能执行,否则会提示跨域安全提示。

b. contenteditable

把contenteditable属性应用给页面中的任何元素,然后用户立即就可以编辑该元素。

设置document.designMode='on'时,页面的任意位置都可以编辑;使用contenteditable='true'则只对具体元素和其包含的元素起作用。

[注意] 一定要区分contenteditable和contentEditable。contenteditable是元素特性,而contentEditable是对象属性。

02. 命令

与富文本编辑器交互的主要方式,就是使用document.execCommand()。这个方法可以对文档执行预定义的命令,而且可以应用大多数格式。

document.execCommand(String aCommandName, Boolean aShowDefaultUI, String aValueArgument)方法需要传递3个参数。

aCommandName表示要执行的命令名称,不可省略。

aShowDefaultUI表示是否展示用户界面,默认为false,可省略。

aValueArgument表示额外参数值,默认为null,可省略。

[注意]为了确保浏览器兼容性,第二个参数应始终设置为false,因为firefox在该参数为true时抛出错误。

a. 段落格式

b. 文本格式

c. 编辑

d. 插入

03. 选区

getSelection()方法

在富文本编辑器中,使用getSelection()方法,可以确定实际选择的文本。这个方法是window对象和document对象的属性,调用它会返回一个表示当前选择文本的Selection对象。每个Selection对象都有下列属性:

[注意] IE8-浏览器不支持。

Selection对象的这些属性并没有包含多少有用的信息。好在,该对象的下列方法提供了更多信息,并且支持对选区的操作。

Selection对象的这些方法都极为实用,它们利用了DOM范围来管理选区。由于可以直接操作选择文本的DOM表现,因此访问DOM范围与使用execCommand()相比,能够对富文本编辑器进行更加细化的控制。如:

以上代码会为富文本编辑器中被选择的文本添加黄色的背景。这里使用了默认选区中的DOM范围,通过surroundContents()方法将选区添加到了带有黄色背景的<span>元素中。

HTML5将getSelection()方法纳入了标准,IE8-浏览器不支持DOM范围,但可以通过它支持的selection对象操作选择的文本。IE中的selection对象是document的属性,要取得富文本编辑器中选择的文本,首先必须创建一个文本范围,然后再像下面这样访问其text属性。

虽然使用IE的文本范围来执行HTML操作并不像使用DOM范围那么可靠,但也不失为一种有效的途径。要像前面使用DOM范围那样实现相同的文本高亮效果,可以组合使用htmlText属性和pasteHTML()方法。

以上代码通过htmlText取得了当前选区中的HTML,然后将其放在了一对<span>标签中,最后又使用pasteHTML()将结果重新插入到了选区中。

04. 表单提交

因为富文本编辑不是使用表单控件实现的,因此富文本编辑器中的HTML不会被自动提交给服务器,而需要手工来提取并提交HTML。为此,通常可以添加一个隐藏的表单字段,让它的值等于从iframe或使用contenteditable属性的元素中提取出的HTML。具体来说,就是在提交表单之前提取出HTML,并将其插入到隐藏的字段中。下面就是通过表单的onsubmit事件处理程序实现上述操作的代码。

在此,通过文档主体的innerHTML属性取得了iframe中的HTML,然后将其插入到了名为"comments"的表单字段中。这样可以确保恰好在提交表单之前填充"comments"字段。如果在代码中通过submit()来手工提交表单,那么一定不要忘记事先执行上面的操作。对于contenteditable元素,也可以执行类似操作。

// 推荐

实现一个富文本编辑器,看似容易,但实际上是一个大工程。

常见在线富文本编辑器:

widgEditor

wangeditor

ueditor


 

表单操作


表单为页面的主要组成部分,其中包含许多的表单控件。用户通过控件提供数据并提交给服务器,服务器则做出相应的处理。而编写一个正常工作的表单需要三个部分:

  1. 构建表单
  2. 服务器处理(提供接受数据接口)
  3. 配置表单

[1] 构建表单

[2] 服务器处理

提供接口地址(例如,https://pizza.example.com/order,数据格式(application/x-www-form-urlencoded),还是接受的参数信息(custname、custtel、custemail、size、topping、delivery)。

数据命名需在表单控件中注明。

[3] 配置表单

用户所有提交的信息需在提交服务器前对其进行验证从而提高用户体验。

NOTE:表单验证 使用 require 来强制用户填写相应的信息。

内容

元素

form 元素

form 元素为构建表单中最重要的元素。

其对应的信息则可以视为

字段
noValidate true
target abc
method post
acceptCharset utf-8
action http://pizza.example.com/order
enctype application/x-www-form-urlencoded
name pizza
autocomplete off

NOTE:前六项为表单提交相关的信息。

属性
  • name 属性:可以用于获取表单节点元素。

  • autocomplete 属性:有两个值 on 与 off,在设置为 on 时,可以自动对输入框进行补全(之前提交过的输入值,下图左)。

NOTE:在已经设置 autocomplete="off" 时依然出现提示框,大多数情况为浏览器设置的自动补全(可以强制关闭,需要时请搜索对应的解决方案)。

  • elements 属性:为一个动态节点集合(更具 DOM 的变化进行变化),其用于归结该表单的子孙表单控件(除图标按钮外 <input type="image>"):

    • button
    • fieldset
    • input
    • keygen
    • object
    • output
    • select
    • textarea

此外还有归属于该表单的空间(依旧图片按键除外)代码如下所示。

  • length 属性:等价于 elements.length 来用于描述表单内节点集合的个数。
选取表单空间元素

选取 name="a" 的控件可以使用下面的方法:

  • form[name] 通过名称作为索引时有如下特点:

    • 返回 id 或者 name 为指定名称的表单空间(图标按键除外)
    • 如果结果为空,则返回id 为指定名称的 img 元素(入下面代码所示)
    • 如果有多个同名元素,则返回的元素为动态节点集合
    • 一旦用指定名称取过改元素,之后则不论该元素的 id 或者 name 如何变化,只有节点存在则均可使用原名称来继续获取改节点。

无指定名称索引范例

更新名称,依然可以获取节点范例

form 接口

form 元素也提供了一些接口便于对其进行操作 reset() submit() checkValidity()

可以重置(reset)的元素有下面的几种:

  • input
  • keygen
  • output
  • select
  • textarea

当触发表单 reset 事件时可使用阻止该事件的默认行为来取消重置。而且元素重置时将不会再次触发元素上的 change 与 input 事件。

label 元素

字段
htmlFor textId
control HTMLElement#textId
form HTMLFormElement#formId
  • htmlFor 属性:用于关联表单控件的激活行为(可使点击 label 与点击表单控件的行为一致),可关联的元素有下列(hidden 除外):

    • button
    • input
    • keygen
    • meter
    • output
    • progress
    • select
    • textarea

自定义文件提交控件样式

  • control 属性:如果指定了 for 属性则指定该for 属性对于 id 的可关联元素。如果没有指定 for 属性则为第一个可关联的子孙元素。

可关联的元素 (只读属性不可在程序中直接赋值修改)

  • button
  • fieldset
  • input
  • keygen
  • label
  • object
  • output
  • select
  • textarea

- form 属性:修改关联元素所归属的表单则可以修改元素的 form 属性为带关联表单Id(元素中对于的for属性也应该做对应的修改)。//这里有一点小问题,更改form属性之后label并不能自动绑定到新表单对应的元素上

input 元素

  • type 属性:可用于控制控件的外观以及数据类型(默认为 text),在不同的浏览器不同数据类型有不同的展示效果。

本地图片预览示例

所需技术点(HTMLInputElement属性)

  • onchange
  • accept
  • multiple
  • files

NOTE:accept 所支持的格式有 audio/* video/* image/* 以及不带;的 MINE Type 类型和 . 开头的文件名后缀的文件。多个文件类型可以使用,分隔。

select 元素

指定选项列表中选择需要的选项。

主要的三个子标签 selectoptgroup(用于选项分组)、option

  • select 具有的属性和方法如下:

    • name
    • value
    • multiple
    • options(动态节点集合)
    • selectedOptions(动态节点集合)
    • selectedIndex
    • add(element[, before])(无指定参照物则添加至最末端)
    • remove([index])
  • optgroup 所具有的属性和方法:

    • disabled (分组选项不可选)
    • label(分组说明)
  • option 所具有的属性和方法:

    • disabled
    • label(描述信息)
    • value(提交表单时的数据信息)
    • text(用户看到的文字)
    • index
    • selected
    • defaultSelected
选项操作

创建选项

添加选项

删除选项

级联下列选择器

所需知识点:

  • onchange
  • remove
  • add

textarea 元素

textarea 具有的属性和方法如下:

  • name
  • value (用户输入信息)
  • select() (全选当前输入的内容)
  • selectionStart (选中的内容的起始位置,无选中时返回当前光标所在位置)
  • selectionEnd (选中内容结束位置,无选中时返回光标位置)
  • selectionDirection (选取方向 forward backward
  • setSelectionRange(start, end[, direction]) (使用程序选中内容)
  • setRangeText(replacement[, start, end, [mode]]) (设置内容范围)
selection

表示选择区域,对于 input 元素同样有效。

selectionDirection 主要是用于在使用 SHIFT 键与方向键组合选取时的选取方向。设置为 forward 时选取移动的方向为 selectionEnd 设置为 backward 时移动方向为 selectionStart

@输入提示示例

所需知识点:

  • oninput
  • selectionStart
  • setRangeText

其他元素
  • fieldset
  • button
  • keygen
  • output
  • progress
  • meter

验证

可以被验证的元素如下所示:】

  • button
  • input
  • select
  • textarea

以下情况不可以做验证

  • input 元素在类型是 hidden, reset, button 时
  • button 元素在类型为 reset, button 时
  • input 与 textarea 当属性为 readonly 时
  • 当元素为 datalist 的子孙节点时
  • 当元素被禁用时 disabled 的状态
属性

验证涉及到以下的以下属性,在每一个可以验证的元素上均可以调用对于的属性或通过接口进行操作:

  • willValidate (表明此元素在表单提交时是否会被验证)
  • checkValidity() (用于验证元素,返回 true 当验证通过,或者触发 invalid 事件)
  • validity (存储验证结果)
  • validationMessage (显示验证异常信息)
  • setCustomValidity(message) (自定义验证错误信息)

自定义异常范例

涉及到的知识点:

  • oninvalid
  • setCustomValidity

禁止验证范例

使用 form 中 novalidate 属性来禁止表单提交的验证。

提交

隐式提交

在操作过程中通过控件的操作来提交表单(敲击回车来提交表单),其需要满足以下的条件:

  • 表单有非禁用的提交按键
  • 没有提交按键时,不超过一个类型为 text search url email password date time number 的 input 元素
提交过程细节

提交过程分为两个阶段,第一个阶段是更具表单 enctype 指定的值构建要提交的数据,第二个阶段是使用指定的方法(method)发送数据到 action 指定的目标。

构建提交数据,从可提交元素中提取数据组成指定数据结构过程(可提交元素有 button input keygen object select textarea

编码方式(enctype)所支持的形式:

  • application/x-www-form-urlencoded (默认,数据格式为 & 分隔的键值对)
  • multipart/form-data (IFC 2388 字节流形式,例如文件上传所使用的数据编码形式)
  • text/plain (回车换行符分隔的键值对)

特殊案例一

当一个表单元素 name="isindex" 并且 type="text" 而且满足如下要求时:

  • 编码格式为 application/x-www-form-urlencoded
  • 作为表单的第一个元素

则提交时只发送 value 值,不包含 name。

特殊案例二

当 name="_charset_" 并且类型为 hidden 时,而且满足如下要求时:

  • 没有设置 value 值

则提交时 value 自动使用当前提交的字符集填充。

submit 接口

form.submit() 可以通过调用接口submit()直接提交表单,在提交表单时均会触发一个 onsubmit 表单提交事件,在这个事件中 women 可以做下面的事件:

  • 提交前的数据验证
  • 阻止事件的默认行为来取消表单的提交(例如当验证失败时)

无刷新表单提交范例

常用的方式是通过 AJAX 进行实现,这里我们使用 iframe 来做中介代理实现。

所需知识点:

  • form
  • target
  • iframe

表单应用

首先需要知道服务器端登陆接口的相关信息,如下所示:

描述 数据信息
请求地址 /api/login
请求参数 telephone 手机号码; password 密码 MD5 加密
返回结果 code 请求状态; result 请求数据结果