表单属性和方法
表单(form)以及例如 <input>
的控件(control)元素有许多特殊的属性和事件。
- 导航:表单和元素
- 文档中的表单是特殊集合
document.forms
的成员。 - 这就是所谓的“命名的集合”:既是被命名了的,也是有序的。我们既可以使用名字,也可以使用在文档中的编号来获取表单。
- 文档中的表单是特殊集合
document.forms.my; // name="my" 的表单
document.forms[0]; // 文档中的第一个表单
当我们有了一个表单时,其中的任何元素都可以通过命名的集合 form.elements
来获取到。
<form name="my">
<input name="one" value="1">
<input name="two" value="2">
</form>
<script>
// 获取表单
let form = document.forms.my; // <form name="my"> 元素
// 获取表单中的元素
let elem = form.elements.one; // <input name="one"> 元素
alert(elem.value); // 1
</script>
这些导航(navigation)属性并不依赖于标签的结构。所有的控件元素,无论它们在表单中有多深,都可以通过 form.elements
获取到。
<body>
<form id="form">
<fieldset name="userFields">
<legend>info</legend>
<input name="login" type="text">
</fieldset>
</form>
<script>
alert(form.elements.login); // <input name="login">
let fieldset = form.elements.userFields;
alert(fieldset); // HTMLFieldSetElement
// 我们可以通过名字从表单和 fieldset 中获取 input
alert(fieldset.elements.login == form.elements.login); // true
</script>
</body>
Fieldset 作为“子表单” 一个表单内会有一个或多个 <fieldset>
元素。它们也具有 elements
属性,该属性列出了 <fieldset>
中的表单控件。
<form id="form">
<input name="login">
</form>
<script>
alert(form.elements.login == form.login); // true,与 <input> 相同
form.login.name = "username"; // 修改 input 的 name
// form.elements 更新了 name:
alert(form.elements.login); // undefined
alert(form.elements.username); // input
// form 允许我们使用两个名字:新的名字和旧的名字
alert(form.username == form.login); // true
</script>
更简短的表示方式:form.name
还有一个更简短的表示方式:我们可以通过 form[index/name]
来访问元素。 换句话说,我们可以将 form.elements.login
写成 form.login
。 这也有效,但是会有一个小问题:如果我们访问一个元素,然后修改它的 name
,之后它仍然可以被通过旧的 name
访问到(当然也能通过新的 name
访问)。
- 反向引用:element.form
- 对于任何元素,其对应的表单都可以通过
element.form
访问到。因此,表单引用了所有元素,元素也引用了表单。
- 对于任何元素,其对应的表单都可以通过
<form id="form">
<input type="text" name="login">
</form>
<script>
// form -> element
let login = form.login;
// element -> form
alert(login.form); // HTMLFormElement
- 表单元素
- input 和 textarea
- 我们可以通过
input.value
(字符串)或input.checked
(布尔值)来访问复选框(checkbox)和单选按钮(radio button)中的value
。
- 我们可以通过
JavaScriptinput.value = "New value"; textarea.value = "New text"; input.checked = true; // 对于复选框(checkbox)或单选按钮(radio button)
- input 和 textarea
使用 textarea.value
而不是 textarea.innerHTML
请注意,即使 <textarea>...</textarea>
将它们的 value
作为嵌套的 HTML 标签来保存,我们也绝不应该使用 textarea.innerHTML
来访问它。 它仅存储最初在页面上的 HTML,而不是存储的当前 value
。
- . select 和 option
- 一个
<select>
元素有 3 个重要的属性select.options
——<option>
的子元素的集合,select.value
—— 当前所选择的<option>
的 value,select.selectedIndex
—— 当前所选择的<option>
的编号。
- 它们提供了三种为
<select>
设置value
的不同方式:- 找到对应的
<option>
元素(例如在select.options
中),并将其option.selected
设置为true
。 - 如果我们知道新的值:将
select.value
设置为对应的新的值。 - 如果我们知道新的选项的索引:将
select.selectedIndex
设置为对应<option>
的编号。
- 找到对应的
- new Option
- 在 规范 中,有一个很好的简短语法可以创建一个
<option>
元素: option = new Option(text, value, defaultSelected, selected); - 参数
text
——<option>
中的文本,value
——<option>
的value
,defaultSelected
—— 如果为true
,那么selected
HTML-特性(attribute)就会被创建,selected
—— 如果为true
,那么这个<option>
就会被选中。
- 一个
聚焦:focus/blur
当用户点击某个元素或使用键盘上的 Tab 键选中时,该元素将会获得聚焦(focus)。还有一个 HTML 特性(attribute)autofocus
可以让焦点在网页加载时默认落在一个元素上,此外还有其它途径可以获得焦点。 失去焦点的时刻(“blur”)可能更为重要。它可能发生在用户点击页面的其它地方,或者按下 Tab 键跳转到下一个表单字段,亦或是其它途径的时候。失去焦点通常意味着:“数据已经输入完成”,所以我们可以运行代码来检查它,甚至可以将其保存到服务器上,或进行其他操作。
- focus/blur 事件
- 当元素聚焦时,会触发
focus
事件,当元素失去焦点时,会触发blur
事件。
html<style> .error { background: red; } </style> Your email please: <input type="email" id="input"> <input type="text" style="width:220px" placeholder="make email invalid and try to focus here"> <script> input.onblur = function() { if (!this.value.includes('@')) { // not email // 显示 error this.classList.add("error"); // ...将焦点放回来 input.focus(); } else { this.classList.remove("error"); } }; </script>
- JavaScript 导致的焦点丢失
- 其中之一就是用户点击了其它位置。当然 JavaScript 自身也可能导致焦点丢失
- 一个
alert
会将焦点移至自身,因此会导致元素失去焦点(触发blur
事件),而当alert
对话框被取消时,焦点又会重新回到原元素上(触发focus
事件)。 - 如果一个元素被从 DOM 中移除,那么也会导致焦点丢失。如果稍后它被重新插入到 DOM,焦点也不会回到它身上。
- 一个
- 其中之一就是用户点击了其它位置。当然 JavaScript 自身也可能导致焦点丢失
- 当元素聚焦时,会触发
- 允许在任何元素上聚焦:tabindex
- 默认情况下,很多元素不支持聚焦。虽然这个范围因浏览器而异,但有一件事总是正确的:用户可以交互的元素:
<button>
,<input>
,<select>
,<a>
等,都支持focus/blur
。 - 另一方面,为了格式化某些东西而存在的元素像
<div>
,<span>
和<table>
—— 默认是不能被聚焦的。elem.focus()
方法不适用于它们,并且focus/blur
事件也绝不会被触发。 - 不具有
tabindex
的元素按文档源顺序(默认顺序)切换。tabindex="0"
会使该元素被与那些不具有tabindex
的元素放在一起。也就是说,当我们切换元素时,具有tabindex="0"
的元素将排在那些具有tabindex ≥ 1
的元素的后面。tabindex="-1"
只允许以编程的方式聚焦于元素。Tab 键会忽略这样的元素,但是elem.focus()
有效。
- 属性
elem.tabIndex
也有效- 我们可以使用
elem.tabIndex
通过 JavaScript 来添加tabindex
。效果是一样的。
- 我们可以使用
- 默认情况下,很多元素不支持聚焦。虽然这个范围因浏览器而异,但有一件事总是正确的:用户可以交互的元素:
- focus/blur 委托
focus
和blur
事件不会向上冒泡。- 需要冒泡效果的时候
- 有一个遗留下来的有趣的特性(feature):
focus/blur
不会向上冒泡,但会在捕获阶段向下传播。 - 可以使用
focusin
和focusout
事件 —— 与focus/blur
事件完全一样,只是它们会冒泡。值得注意的是,必须使用elem.addEventListener
来分配它们,而不是on<event>
。
- 有一个遗留下来的有趣的特性(feature):
事件:change,input,cut,copy,paste
- 事件:change
- 当元素更改完成时,将触发
change
事件。 - 对于文本输入框,当其失去焦点时,就会触发
change
事件。 - 对于其它元素:
select
,input type=checkbox/radio
,会在选项更改后立即触发change
事件。
- 当元素更改完成时,将触发
- 事件:input
- 每当用户对输入值进行修改后,就会触发
input
事件。 - 与键盘事件不同,只要值改变了,
input
事件就会触发,即使那些不涉及键盘行为(action)的值的更改也是如此:使用鼠标粘贴,或者使用语音识别来输入文本。 - 无法阻止
oninput
中的任何事件- 当输入值更改后,就会触发
input
事件。 - 所以,我们无法使用
event.preventDefault()
—— 已经太迟了,不会起任何作用了。
- 当输入值更改后,就会触发
- 每当用户对输入值进行修改后,就会触发
- 事件:cut,copy,paste
- 这些事件发生于剪切/拷贝/粘贴一个值的时候。
- 它们属于 ClipboardEvent 类,并提供了对剪切/拷贝/粘贴的数据的访问方法。
- 我们也可以使用
event.preventDefault()
来中止行为,然后什么都不会被复制/粘贴。
- 安全限制
- 剪贴板是“全局”操作系统级别的东西。用户可能会在各种应用程序之间切换,复制/粘贴不同的内容,而浏览器页面不应该能访问这些内容。
- 因此,大多数浏览器仅允许在某些用户操作范围内(例如复制/粘贴等)对剪切板进行无缝的读/写访问。
- 除火狐(Firefox)浏览器外,所有浏览器都禁止使用
dispatchEvent
生成“自定义”剪贴板事件,即使我们设法调度此类事件。规范也明确声明了,合成(syntetic)事件不得提供对剪切板的访问权限。 - event.clipboardData 仅在用户启动的事件处理程序的上下文中生效。
- navigator.clipboard 是一个较新的 API,适用于任何上下文。如果需要,它会请求用户的许可。
表单:事件和方法提交
提交表单时,会触发 submit
事件,它通常用于在将表单发送到服务器之前对表单进行校验,或者中止提交,并使用 JavaScript 来处理表单。 form.submit()
方法允许从 JavaScript 启动表单发送。我们可以使用此方法动态地创建表单,并将其发送到服务器。
- 事件:submit
- 提交表单主要有两种方式
- 第一种 —— 点击
<input type="submit">
或<input type="image">
。 - 第二种 —— 在
input
字段中按下 Enter 键。
- 第一种 —— 点击
- 这两个行为都会触发表单的
submit
事件。处理程序可以检查数据,如果有错误,就显示出来,并调用event.preventDefault()
,这样表单就不会被发送到服务器了。 submit
和click
的关系- 在输入框中使用 Enter 发送表单时,会在
<input type="submit">
上触发一次click
事件。在输入框输入内容之后Enter,没点击,但是会触发一次click事件。
- 在输入框中使用 Enter 发送表单时,会在
- 提交表单主要有两种方式
- 方法:submit
- 如果要手动将表单提交到服务器,我们可以调用
form.submit()
- 如果要手动将表单提交到服务器,我们可以调用