019 表单
# 基础
Web 表单在HTML 中以<form>元素表示,在JavaScript 中则以HTMLFormElement类型表示。
HTMLFormElement接口可以创建或者修改<form>对象;它继承了HTMLElement接口的方法和属性HTMLFormElement的主要属性和方法:
| 属性值 | 说明 |
|---|---|
| acceptCharset | 服务器可以接收的字符集,如UTF-8 |
| action | 请求的URL |
| elements | 表单中所有控件的HTMLCollection |
| enctype | 规定在将表单数据发送到服务器之前如何对其进行编码 |
| length | 表单中控件的数量 |
| method | 请求方法类型,如get/post/put/del |
| name | 表单的名字 |
| reset() | 把表单字段重置为各自的默认值 |
| submit() | 提交表单 |
| target | 用于发送请求和接收响应的窗口的名字 |
enctype 的属性值及说明:
| 属性值 | 说明 |
|---|---|
| application/x-www-form-urlencoded | 默认。在发送前对所有字符进行编码(将空格转换为 "+" 符号,特殊字符转换为 ASCII HEX 值)。 |
| multipart/form-data | 不对字符编码。当使用有文件上传控件的表单时,该值是必需的。 |
| text/plain | 将空格转换为 "+" 符号,但不编码特殊字符。 |
# 提交表单
可以通过按钮提交<button type="submit">Submit Form</button>,表单校验 可以通过监听submit事件实现,通过preventDefault方法阻止表单提交。
let form = document.getElementById("myForm");
form.addEventListener("submit", (event) => {
// 阻止表单提交
event.preventDefault();
});
2
3
4
5
也可以通过form.submit()方法提交表单,但不会触发submit事件,调用这个方法前要先做数据验证!
# 重置表单
通过按钮触发<button type="reset">Reset Form</button> 或 直接调用form.reset()
# 表单字段
所有表单元素都包含在form.elements属性中,elements 集合是一个有序列表,每个字段都以它们在HTML 标记中出现的次序保存。
let form = document.getElementById("form1");
// 取得表单中的第一个字段
let field1 = form.elements[0];
// 取得表单中名为"textbox1"的字段
let field2 = form.elements["textbox1"];
2
3
4
5
一个不常用的HTML标签
<fieldset></fieldset>用于将表单字段进行分组,会生成一个边框和标题
表单字段的公共属性:
| 属性值 | 说明 |
|---|---|
| disabled | 是否禁用 |
| readOnly | 是否只读 |
| name | 字段的名字 |
| type | 字段类型(password/submit等详见w3c (opens new window))默认text |
| value | input的值;对于文件上传来说是只读的仅包含计算机上某个文件的路径 |
| form | 指针,指向表单字段所属的表单 |
| tabIndex | 表示这个字段在按Tab 键时的切换顺序 |
表单字段的公共事件:
focus: 获得焦点
blur:失去焦点
change: 在
<input>和<textarea>元素的value 发生变化且失去焦点时触发,或者在<select>元素中选中项发生变化时触发。
# 文本框编程
多行文本: <textarea>会创建多行文本框。rows 属性指定文本框高度;以cols 属性指定文本框宽度。<textarea>的初始值必须包含在标签内,如:<textarea rows="25" cols="5">initial value</textarea>
选择文本: 通过select()方法可以选中输入框文本,方便用户一次性删除
取得选中文本: selectionStart 和selectionEnd
function getSelectedText(textbox){
return textbox.value.substring(textbox.selectionStart,
textbox.selectionEnd);
}
2
3
4
部分选中文本:element.setSelectionRange(selectionStart, selectionEnd [, selectionDirection]); MDN (opens new window)
textbox.value = "Hello world!"
// 选择所有文本
textbox.setSelectionRange(0, textbox.value.length); // "Hello world!"
// 选择前3 个字符
textbox.setSelectionRange(0, 3); // "Hel"
// 选择第4~6 个字符
textbox.setSelectionRange(4, 7); // "o w"
2
3
4
5
6
7
# 输入过滤
通过监听keypress实现输入过滤
textbox.addEventListener("keypress", (event) => {
if (!/\d/.test(String.fromCharCode(event.charCode)) && event.charCode > 9 && !event.ctrlKey){ // 输入的charCode为数字,并且charCode大于9用于避开功能键,并且不是ctrl组合键
event.preventDefault();// 让文本框忽略非数字输入
}
});
2
3
4
5
# 自动切换
在遇到有区号的情况下,可以通过自动切换到下一文本框提高用户体验,如:
function tabForward(event) {
let target = event.target;
if (target.value.length == target.maxLength) {
let form = target.form;
for (let i = 0, len = form.elements.length; i < len; i++) {
if (form.elements[i] == target) {
if (form.elements[i + 1]) {
form.elements[i + 1].focus();
}
return;
}
}
}
}
let inputIds = ["txtTel1", "txtTel2", "txtTel3"];
for (let id of inputIds) {
let textbox = document.getElementById(id);
textbox.addEventListener("keyup", tabForward);
}
let textbox1 = document.getElementById("txtTel1");
let textbox2 = document.getElementById("txtTel2");
let textbox3 = document.getElementById("txtTel3");
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 表单序列化
表单序列化的代码如下
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.attributes["value"].specified ?
option.value : option.text);
}
parts.push(encodeURIComponent(field.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)}');
}
}
return parts.join("&");
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
这个函数的最后一步是使用join()通过和号把所有字段的名值对拼接起来。serialize()函数返回的结果是查询字符串格式。
# 富文本编辑
# designMode
富文本编辑的技术就是在空白HTML 文件中嵌入一个 iframe。通过designMode 属性,可以将这个空白文档变成可以编辑的,实际编辑的则是<body>元素 的HTML。designMode 属性有两个可能的值:"off"(默认值)和"on"。设置为"on"时,整个文档 都会变成可以编辑的(显示插入光标),从而可以像使用文字处理程序一样编辑文本,通过键盘将文本 标记为粗体、斜体,等等。
<iframe name="richedit" style="height: 100px; width: 100px"></iframe>
<script>
window.addEventListener("load", () => {
frames["richedit"].document.designMode = "on";
});
</script>
2
3
4
5
6
# contenteditable
任何元素指定contenteditable 属性,即可将元素转为可编辑状态,如<div contenteditable="true"></div>。元素中包含的任何文本都会自动被编辑, 元素本身类似于<textarea>元素。也可以通过js随时改变该元素的编辑状态。
tip: contenteditable 是一个非常多才多艺的属性。比如,访问伪URL data:text/html,
可以把浏览器窗口转换为一个记事本。这是因为这样会临时创建DOM树并将整个文档变成可编辑区域。
# 富文本交互
与富文本编辑器交互的主要方法是使用document.execCommand()。目前该API已废弃,像wangeditor也是基于此API开发。详细可以看一下这篇房极客技术团队-document.execCommand的探索 (opens new window)
如何提交?
通过表单隐藏字段,使用contenteditable元素的HTML更新其值。如
form.addEventListener("submit", (event) => {
let target = event.target;
target.elements["comments"].value =
frames["richedit"].document.body.innerHTML;
});
2
3
4
5