## 表单 Web表单是开发人员与用户交互的重要控件。 **1、form** **1.1 form独有的属性和方法** 在HTML中,表单是由`<form>`来表示的,而在JavaScript中,表单对应的是HTMLFormElement类型。HTMLFormElement继承了HTMLElement,因此它跟其他HTML元素具有相同的默认属性。 `<form>`也有自己独有的属性和方法: ``` acceptCharset:服务器能够处理的字符集 action:接收请求的URL elements:表单中所有控件的集合(HTMLCollection) enctype:请求的编码类型 length:表单中控件的数量 method:要发送的HTTP请求类型,通常是“get”或“post” name:表单的名称 reset():将所有表单域重置为默认值 submit():提交表单 target:用于发送请求和接收响应的窗口名称 ``` **1.2 获取表单元素** 获取表单元素一般有两种方式: - 通过id来获取,比如获取一个id名为form1的表单元素: ``` document.getElementById('form1'); ``` -通过docuemnt.forms获取name名为form1的表单元素: ``` document.forms['form1] ``` `document.forms`可以获取到当前页面中所有的表单元素,我们又可以通过方括号表示法获取某个属性,传入数值索引或`name`值。 **1.3 提交表单** 提交表单也有两种方式: - 通过`<input>`或`<button>`提交: ``` <input type="submit" /> <button type="submit"></button> <input type="image" src="example.png" /> ``` 只要`<form>`内有上面这三种按钮,点击的时候就会提交表单,而且,当相应表单控件拥有焦点时,按回车键也会提交表单(焦点在textarea里例外,回车键是换行)。 - 通过JavaScript触发submit()提交: ``` var form1 = document.getElementById('form1'); form1.submit(); ``` 在请求发送给服务器之前,浏览器会触发submit事件,我们可以主动监听它: ``` var form1 = document.getElementById('form1'); form1.onsubmit = function(){ } ``` 注意:在调用submit()方法提交表单时,不会触发submit事件。 **1.4 重置表单** 重置表单也有两种方式: - 重置按钮 ``` <input type="reset" /> <button type="reset"></button> ``` 当点击重置按钮时,会触发reset事件: ``` form1.onreset = function(){ } ``` - 通过reset()方法 ``` form1.reset(); ``` 与调用submit()不同,调用reset()方法时也会触发reset事件。 **1.5 表单字段** 除了使用原生DOM方法访问表单元素外,每一个表单都有elements属性,该属性是表单中所有元素的集合(比如`<input>、<textarea>、<button>、<fieldset>`),elements是一个有序列表,包含着表单中的所有字段。 ``` <form id="form1"> <input type="text" name="yourname" /> <textarea name="intro"></textarea> </form> form1.elements[0] // 取得表单中的第一个字段 form1.elements['yourname']; // 取得name名为“yourname”的字段 ``` 如果表单内有多个同名(name)表单控件,那么用name取时,就会返回一个NodeList集合。 ``` <form id="form1"> <input type="radio" name="color" /> red <input type="radio" name="color" /> green </form> var colors = form1.elements['color'] ``` colors是一个NodeList集合,包含了上面两个radio。 **1.5.1 表单字段的共有属性** 除了`<fieldset>`元素,所有表单字段都拥有一些相同的属性。 共有的属性和方法: ``` disabled:布尔值,表单当前字段是否被禁用 form:指向当前字段所属表单的指针,只读 name:当前字段的名称 readonly:布尔值,表示当前字段是否只读 tabIndex:表单当前字段的切换(tab)序号 type:当前字段的类型 value:当前字段将被提交给服务器的值。 ``` `<input>`和`<button>`元素的type属性是可以修改,但`<select>`元素则是只读的。 **1.5.2 表单字段的共有方法** 每个表单字段都有两个方法:focus()和blur()。 - focus()方法用于让表单字段获取到焦点 - blur()方法用于让表单字段失去焦点 HTML5新增了一个autofocus属性,作用相当于focus(),只要设置了此属性,表单字段就会自动获取焦点。 **1.5.3 表单字段的共有事件** 所有表单都支持下列三个事件: - blur:当前字段失去焦点时触发 - change:对于`<input>、<textarea>`元素,在它们失去焦点且value值改变时触发,对于`<select>`元素,在选项改变时触发 - focus:当前字段获得焦点时触发 如果你要实时的监听表单字段的值是否变化,可使用如下代码: ``` if('oninput' in docuemnt){ input.addEventListener('input',function(){}); }else{ input.onpropertychange = function(){}; } ``` 当支持input事件时,就使用input,否则使用onpropertychange(IE特有) **onchange、oninput和onpropertychange三个事件的区别**: `onchange`事件在内容改变(两次内容有可能还是相等的)且失去焦点时触发; `oninput`事件是IE之外的大多数浏览器支持的事件,在value改变时触发,实时的,即每增加或删除一个字符就会触发,然而通过js改变value时,却不会触发; `onpropertychange`事件是任何属性改变都会触发的,而oninput却只在value改变时触发,oninput要通过addEventListener()来注册。 **失效情况**: - oninput事件: 当脚本中改变value时,不会触发;从浏览器的自动下拉提示中选取时,不会触发。 - onpropertychange事件:当input设置为disabled=true后,onpropertychange不会触发。 **2、文本框** 文本框有两种:`<input>`和`<textarea>`。 ``` <input type="text" /> <textarea cols ="10" rows ="5"></textarea> ``` **2.1 文本框独有的属性** `<input>`的独有属性: ``` size:指定文本框能够显示的字符数 maxlength:指定文本框可以接受的最大字符数 ``` 对于`<textarea>`,它还有一些独有属性: ``` rows:指定的文本框的字符行数 cols:指定的文本框的字符列数 ``` 注意:`<textarea>`的初始值是放在`<textarea>`和`</textarea>`之间的。 **2.2 选择文本** 文本框都支持select()方法,用于选择文本框中的所有文本。当调用select()方法时,大多数浏览器都会将焦点设置到文本框中。 当用户选择了文本框中的文本时,会触发select事件。 ``` input.addEventListener('select',function(){}); ``` **2.2.1 取得选择的文本** 在支持HTML5的浏览器中,我们可以获取到用户选择了什么文本,通过两个属性:selectionStart和selectionEnd,这两个属性保存的是基于0的数值,表示所选择文本的范围。 取得用户选择的文本: ``` function getSelectedText(textbox){ if(typeof textbox.selectionStart == 'number'){ return textbox.value.substring(textbox.selectionStart, textbox.selectionEnd); }else if(document.selection){ return document.selection.createRange().text; } } ``` IE8之前不支持selectionStart。 **2.2.2 选择部分文本** 所有文本框都有一个`setSelectionRange()`方法(支持HTML5的浏览器中),它接受两个参数:要选择的第一个字符的索引和要选择的最后一个字符的索引。 不过在IE8及之前的版本并不支持这个方法。当然,也有替代的方法。 在IE上,我们使用`createTextRange()`创建一个范围,然后使用`moveStart()`和`moveEnd()`方法将这个范围移动到需要获取文本的位置上。不过,在使用这两个方法之前,还必须使用`collpase()`将范围折叠刀文本框的开始文章,此时,`moveStart()`将范围的起点和终点都移动到了相同的位置,只要再给`moveEnd()`传入要选择的字符总数即可。最后一步,就是使用范围的`select()`方法选择文本。 ``` function selectText(textbox, startIndex, stopIndex){ if(textbox.setSelectionRange){ textbox.setSelectionRange(startIndex, stopIndex); }else if(textbox.createTextRange()){ var range = document.createTextRange(); range.collapse(true); range.moveStart('character', startIndex); range.moveEnd('character', stopIndex - startIndex); range.select(); } textbox.focus(); } ``` `moveStart()`和`moveEnd()`两个方法其实可用看做是`setSelectionRange()`的两个分解方法,获取开始点和获取结束点。 **2.2.3 过滤输入** 对于很多文本框来说,都不会任由用户输入文本,或多或少都会有所限制,这个时候,我们就需要监听`keypress`键盘事件,通过`event`事件对象中的字符编码`keyCode`来判断输入字符是否该被屏蔽 ``` textbox.addEventListener('keypress', function(event){ var keycode = event.keyCode; }); ``` **2.2.4 操作剪贴板** 剪切板事件: - `beforecopy`:在发生复制操作前触发 - `copy`:在发生复制操作时触发 - `beforecut`:在发生剪切操作前触发 - `cut`:在发生剪切操作时触发 - `beforepaste`:在发生黏贴操作前触发 - `paste`:在发生黏贴操作时触发 要访问剪切板中的数据,可以使用`clipboardData`对象,在IE下,这个对象是`window`属性,在其他浏览器,这个对象是相应`event`对象的属性。 注意:在IE中,可以随时访问`clipboardData`对象;在其他浏览器中,只有在处理剪贴板事件期间`clipboardData`对象才有效。 `clipboardData`对象有三个方法: - getData():用于从剪切板中取得数据,它接受一个参数,即要取得的数据的格式。在IE中,有两种数据格式:“text”和“URL”;在其他浏览器中,这个参数是一种MIME类型,比如“text/plain”,不过可以使用“text”代替“text/plain” - setData():用于放置剪切板中的文本,它接受两个参数,第一个参数是数据格式(和getData()中的数据格式一样,IE支持“text”和“URL”,其他浏览器只支持MIME类型),第二个参数是要放在剪切板中的文本。成功的将文本放到剪切板后,都会返回true。 clearData():用于删除剪切板中指定格式的数据,它接受一个参数,即要删除数据的格式。 ``` function getClipboardText(event){ var clipboardData = (event.clipboardData || window.clipboardData); return clipboardData.getData('text'); } function setClipboardText(event, value){ if(event.clipboardData){ return event.clipboardData.setData('text/plain', value); }else if(window.clipboardData){ return window.clipboardData.setData('text', value); } } ``` **2.2.5 HTML5 约束验证 API** HTML5位表单字段提供了自动验证的功能,当然,要使用这些功能,开发者必须指定一些约束。 **(1)必填字段** 可以使用`required`属性来将字段定位必填字段: ``` <input type="text" required /> ``` 只要设置了`required`属性,这个表单字段就不能为空。 当然,我们也可以使用JavaScript来获取或设置字段是否必填: ``` document.forms[0].elements['name'].required ``` 由于是HTML5中定义的,我们有时需要检测浏览器是否支持: ``` if( 'required' in document.createElement('input') ){ } ``` **(2)输入模式** HTML5位文本字段新增了`pattern`属性,这个属性的值是一个正则表达式,用于匹配文本框中的值 ``` <input type="text" pattern="\d+" /> ``` **(3)检测有效性** 使用`checkValidity()`方法可以检测表单中的某个字段是否有效。所有表单字段都有这个方法,如果字段的值有效,则返回true,否则返回false。 ``` if( document.forms[0].elements[0].checkValidity() ){} ``` 当然,如果要检测整个表单是否有效,可以在表单自身调用这个方法,当所有表单字段有效,才返回true,只要有一个字段无效,则返回false。 ``` if( document.forms[0].checkValidity() ){} ``` 每个表单字段还有一个更有效的的属性:validity,它包含了一系列属性,每个属性会返回一个布尔值 ``` customError:如果设置了setCustomValidity(),则为true,否则为false。 patternMismatch:如果值与指定的pattern属性不匹配,返回true rangeOverflow:如果值比max值大,返回true rangeUnderflow:如果值比min值小,返回true stepMisMatch:如果min和max之间的步长值不合理,返回true tooLong:如果值的长度超过了maxlength属性指定的长度,返回true typeMismatch:如果值不是“mail”或“url”要求的格式,返回true valid:如果这里的其他属性都是false,返回true valueMissing:如果标注为required的字段中没有值,返回true ``` 例子: ``` if( input.validity && !input.validity.valid){ } ``` **(4)禁用验证** 通过设置`novalidate`属性,可以告诉表单不进行验证。 ``` <form novalidate></form> ``` 当然,也可以通过JavaScript设置: ``` document.forms[0].noValidate = true; // 禁用验证 ``` 我们也可以通过给提交按钮添加`formnovalidate`属性来禁用验证 ``` <form> <input type="submit" formnovalidate /> </form> ``` **3、选择框** HTML中的选择框通过`<select>`和`<option>`元素创建。 `<select>`属于HTMLSelectElement类型,有下列的独有属性和方法: - add(newOption, relOption):向控件中插入新的`<option>`元素,其位置在相关项(relOption)之前。 - multiple:布尔值,表示是否允许多项选择 - options:控件中所有`<option>`元素的HTMLCollection。 - remove(index):移除给定位置的选项 - selectedIndex:基于0的选中项的索引,如果没有选中项,则值为-1;对于多选项来说,只保存选中项中第一项的索引 - size:选择框中可见的行数 选择框的type属性不是“select-one”,就是“select-multiple”。 选择框的value属性由当前选中项决定,相应规则如下: - 如果没有选中的项,则选择框的value属性保存空字符串 - 如果有一个选中项,而且该项的value属性已经制定,则选择框的value等于选中项的value属性的值 - 如果有一个选中项,但该项的value属性没有指定,则选择框的value等于该项的文本 - 如果有多个选中项,则选择框的value将依据前两条规则取得第一个选中项的值。 在DOM中,每个`<option>`元素都有一个HTMLOptionElement对象,其有下列属性: - index:当前选项在options集合中的索引 - label:当前选项的标签 - selected:布尔值,表示当前选项是否被选中。将其设置为true可以选中该项 - text:选项的文本 - value:选项的值