表单脚本
表单基础
Web 表单在 HTML 中以 元素表示,在 JavaScript 中则以 HTMLFormElement 类型表示。
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 属性。
取得对 元素的引用。
// 通过 id 获取表单引用
let form = document.getElementById("form1");
// 通过索引获取表单引用
let firstForm = document.forms[0];
// 通过表单 name 属性获取引用
let xkcForm = document.forms["xkcForm"];
提交表单
表单的提交按钮可以使用 type 属性为 “submit” 的 或 元素来定义,图片按钮可以使用 type 属性为 “image” 的 元素来定义。
<!-- 通用提交按钮 -->
<input type="submit" value="Submit Form">
<!-- 自定义提交按钮 -->
<button type="submit">Submit Form</button>
<!-- 图片按钮提交 -->
<input type="image" src="xkc.png">
表单上有任意一种提交按钮,且焦点在表单中某个控件上,按回车键可以提交表单(textarea 控件忽略,回车键不发生提交,而是发生换行)。
阻止默认行为可以取消提交表单。
let form = document.getElementById("xkcForm");
form.addEventListener("submit", function(event) {
event.preventDefault();
});
可以调用 submit()
方法来提交表单。
form.submit();
注意:
通过 submit()
方法提交表单时, submit 事件不会触发。 因此需要在 submit()
方法前面先进行提交数据验证。
多次提交表单的解决方式:
- 在表单提交后禁用提交按钮;
- 通过
onsubmit
事件处理程序取消之后的表单提交。
重置表单
重置按钮可以使用 type 属性为 “reset” 的 或 元素来创建。
<!-- 通用重置按钮 -->
<input type="reset" value="Reset Form">
<!-- 自定义重置按钮 -->
<button type="reset">Reset Form</button>
重置表单之后,整个表单会重置回第一次渲染时的状态。
阻止重置表单行为,可以通过阻止默认行为
let form = document.getElementById("xkc");
form.addEventListener("reset", (event) => {
event.preventDefault();
});
重置表单可以通过调用 reset()
方法来完成。
form.reset();
注意:
与 submit()
方法不同的是,调用 reset()
方法会触发 reset 事件。一般不推荐重置表单的操作。
表单字段
所有表单都是表单 elements 属性中包含的一个值。这个 elements
集合是一个有序列表,包含对表单中所有字段的引用。可以通过索引位置和 name 属性来访问。
let form = document.getElementById("xkcForm");
// 根据索引获取
let field1 = form.elements[0];
// 根据 name 属性获取
let field2 = form.elements["text1"];
let fieldCount = form.elements.length;
表单字段的公共属性:
disabled
:布尔值,表示表单字段是否禁用。form
:指针,指向表单字段所属的表单。只读。name
:字符串,这个字段的名字。readOnly
:布尔值,表示这个字段是否只读。tabIndex
:数值,表示这个字段在按 Tab 键时的切换顺序。type
:字符串,表示字段类型。value
:要提交给服务器的字段值。只读。
表单字段的公共方法:
两个公共方法:focus()
和 blur()
。
-
focus()
:把浏览器焦点设置到表单字段。如果被修改的字段是 type 是 “hidden” 的 元素,或者该字段被 CSS 属性 display 或 visibility 隐藏了,则报错。HTML5 为表单字段增加了
autofocus
属性,支持的浏览器会自动为带有该属性的元素设置焦点。该属性是布尔值。注意:
默认下只能给表单元素设置焦点。也可以通过将 tabIndex 属性设置为 -1 再调用
focus()
可以给任意元素设置焦点。 -
blur()
:用于从元素上移除焦点。
表单字段的公共事件:
blur
:在字段失去焦点时触发。change
:在 和 元素的 value 发生变化且失去焦点时触发,在 元素被选中时发生变化时触发。focus
:在字段获得焦点时触发。
blur 和 focus 事件会因为用户手动改变字段焦点或者使用 blur()
或 focus()
方法而触发。
文本框编程
选择文本
select()
方法用于全部选中文本框中的文本。
select 事件
select
事件在当选中文本框中的文本时,会触发。
取得选中文本
为提供选中文本信息。 HTML5 对此进行了扩展,为文本框添加了两个属性:selectionStart
和 selectionEnd
。分别表示文本选区的起点和终点(文本选区起点的偏移量和文本选区终点的偏移量)。
老版本IE有包含整个文档中文本选择信息的 document.selection
对象。必须先创建一个范围。再从中取得文本。
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;
}
}
部分选中文本
HTML5 在文本框中选中部分文本提供支持。 setSelectionRange()
方法也可以在所有文本框中使用。这个方法接收两个参数:要选择的第一个字符的索引和停止选择的字符的索引。
注意:
在调用 setSelectionRange()
方法之前要先给文本框设置焦点。
IE早期版本提供的 createTextRange()
方法创建一个范围,并使用 moveStart()
和 moveEnd()
范围方法。在使用这两个方法之前需要先调用 collapse()
方法把范围折叠到文本框的开始。接着,moveStart()
可以把范围的起点和终点都移动到相同的位置,再给 moveEnd()
传入要选择的字符总数作为参数。最后使用 select()
选中文本。
let textbox = document.forms[0].elements["textbox1"];
textbox.value = "Hello World!";
var range = textbox.createTextRange();
range.collapse(true);
range.moveStart("charactor", 0);
range.moveEnd("charactor", textbox.value.length);
range.select(); // Hello World!
range.collapse(true);
range.moveStart("charactor", 0);
range.moveEnd("charactor", 3);
range.select(); // Hel
注意:
要想看到效果文本框必须先获得焦点。
输入过滤
屏蔽字符
例
// 用户输入手机号文本框不应该出现非数字字符
textbox.addEventListener("keypress", (event) => {
if (!/\d/.test(String.fromCharCode(event.charCode)) && event.charCode > 9 && !event.ctrlKey) {
event.preventDefault();
}
});
处理剪贴板
剪贴板相关事件:
beforecopy
:复制操作发生前触发。copy
:复制操作发生时触发。beforecut
:剪切操作发生前触发。cut
:剪切操作发生时触发。beforepaste
:粘贴操作发生前触发。paste
:粘贴操作发生时触发。
剪贴板上的数据可以通过 window 对象(IE) 或 event 对象(Firefox、Safari 和 Chrome) 上的 clipboardData
对象获取。Firefox、Safari 和 Chrome 中只能再剪贴板事件期间访问 clipboardData 对象。IE 在任何时候都会暴露 clipboardData
对象。
兼容的获取和设置剪贴板内容
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);
}
}
HTML5 约束验证 API
必填字段
给表单字段添加 required 属性。
<input type="text" name="xkcName" required >
任何带有 required
属性的字段必须有值,否则无法提交表单。
可通过检测对应元素的 required
属性来判断表单字段是否为必填。
let isXkcNameRequired = document.forms[0].elements["xkcName"].required;
更多输入类型
新的输入类型 “email” 和 “url”。
<input type="email" name="email">
<input type="url" name="url">
数值范围
HTML5 定义了其他几种新的输入元素类型。包括:“number”、“range”、“datetime”、“datetime-local”、“date”、“month”、“week” 和 “time”。并非所有主流浏览器都支持。
对于上述每种数值类型。都可以指定 min 属性(最小可能值)、max 属性(最大可能值),以及 step 属性(从 min 到 max 的步长值)。
<!-- 只允许输入 0 到 100 中 5 的倍数 -->
<input type="number" min="0" max="100" step="5" name="xkc">
stepUp()
和 stepDown()
接收一个可选参数:要从当前值加上或减去的数值。(默认,步长会增加或递减 1 )。
input.stepUp(); // 加 1
input.stepUp(2); // 加 2
input.stepDown(); // 减 1
input.stepDown(2); // 减 2
输入模式
HTML 新增 pattern 属性。用于指定一个正则表达式,用户输入的文本必须与之匹配。
<input type="text" pattern="\d+" name="count">
可以使用元素的 pattern 属性获取
let pattern = document.form[0].elements["count"].pattern;
检测有效值
使用 checkValidity()
方法可以检测表单中任意给定字段是否有效。这个方法在所有表单元素上都可以使用,字段有效则返回 true,否则返回 false。判断字段是否有效依据是上面的约束条件。
checkValidity()
方法只会告诉我们字段是否有效,而 validity
属性会告知我们字段为什么有效或者无效。validity
属性是一个对象,包含返回布尔值的属性:
customError
:如果设置了setCustomValidity()
就返回 true,否则返回 false。patternMismatch
:如果字段值不匹配指定的 pattern 属性则返回 false。rangeOverflow
:如果字段值大于 max 的值则返回 true。rangeUnderflow
:如果字段小于 min 的值则返回 true。stepMisMatch
:如果字段值与 min、max 和 step 的值不相符则返回 true。tooLong
:如果字段值的长度超过 maxlength 属性指定的值则返回 true。typeMismatch
:如果字段值不是 “email” 或 “url” 要求的格式返回 true。valid
:如果其他所有属性值都是 false 或者 true 。与checkValidity()
条件一致。valueMissing
:如果字段是必填的但没有值则返回 true。
禁用验证
通过指定 novalidate
属性可以禁止对表单进行任何验证:
<form method="post" action="" novalidate></form>
如果一个表单有多个提交按钮,可以给特定的提交按钮添加 formnovalidate
属性,指定通过该按钮无须验证便可提交表单。
<form method="post" action="">
<input type="submit" value="Submit 1">
<input type="submit" formnovalidate value="Submit 2">
</form>
选择框编程
选择框是使用 和 元素创建的。
add(newOption, relOption)
:在 relOption 之前向控件中添加新的 。multiple
:布尔值。表示是否允许多选,等价于 HTML 的 multiple 属性。options
:控件中所有 元素的 HTMLCollection。remove(index)
:移除给定位置的选项。selectedIndex
:选中项基于 0 的索引值,如果没有选中项则为 -1 。对于允许多选的列表,始终是第一个选项中的索引。size
:选择框中可见的行数,等价于 HTML 的 size 属性。
以下规则决定选择框的 value 属性
- 如果没有选中项,选择框的值是空字符串。
- 如果有一个选中项,且其 value 属性有值,则选择框的值就是选中项 value 属性的值。即使 value 属性的值是空字符串也是如此。
- 如果有一个选中项,且其 value 属性没有指定值,则选择框的值就是该项的文本内容。
- 如果有多个选中项,则选择框的值根据前两条规则取得第一个选中项的值。
每个 元素的属性:
- index:选项在 options 集合中的索引。
- label:选项的标签,等价于 HTML 的 label 属性。
- selected:布尔值,表示是否选中了当前选项。把这个属性设置为 true 会选中当前选项。
- text:选项的文本。
- value:选项的值(等价于 HTML 的 value 属性)。
选项处理
只允许选择一项的选择框中,获取选项最简单的方式就是使用选择框的 selectedIndex 属性。
let selectbox = document.forms["xkcForm"].elements["xkcSelect"];
let selectedOption = selectbox.options[selectbox.selectedIndex];
允许多选的选择框, selectedIndex 属性就像只允许选择一项一样。设置 selectedIndex 会移除所有选项,只选择指定的项,而获取 selectedIndex 只会返回选中的第一项的索引。
添加选项
创建 元素节点并设置 value 和 text,并添加到选择框中。
let newOption = document.createElement("option");
newOption.appendChild(document.createTextNode("Option Text"));
newOption.setAttribute("value", "Option Value");
selectbox.appendChild(newOption);
使用 Option 构造函数创建新选项。接收两个参数:text 和 value,其中 value 是可选的。返回一个元素。
let newOption = new Option("Option text", "Option Value");
selectbox.add(newOption, undefined);
移除选项
第一种使用 DOM 的 removeChild()
方法并传入要移除的选项。
selectbox.removeChild(selectbox.options[0]);
第二种使用 remove() 方法。
selectbox.remove(0);
最后一种将选项设置为 null 。
selectbox.options[0] = null;
移动和重排选项
使用 insertBefore()
方法。
let optionMove = selectbox.option[1];
selectbox.insertBefore(optionMove, selectbox.options[optionMove.index - 1]);
表单序列化
function serialize(form) {
let parts = [];
let optValue;
for (let field of form.elements) {
switch (field.type) {
case "select-one":
case "select-multiple":
if (field.name.length) {
for (let option of field.options) {
if (option.selected) {
if (option.hasAttribute) {
optValue = (option.hasAttribute("value") ? option.value : option.text);
} else {
optValue = (option.attribute["value"].specified ? option.value : option.text);
}
parts.push(encodeURIComponent(filed.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) {
parts.push(`${encodeURIComponent(field.name)}=${encodeURIComponent(field.value)}`);
}
}
}
}