019 表单

7/8/2021 Javascript

# 基础

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();
});
1
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"];
1
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);
}
1
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"
1
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();// 让文本框忽略非数字输入
}
});
1
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");
1
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("&");
}
1
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>
1
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;
});
1
2
3
4
5
Last Updated: 8/4/2021, 6:25:04 PM