[TOC]
# 表单的基础知识
在 HTML 中,表单是由`<form>`元素来表示的,而在 JavaScript 中,表单对应的则是 HTMLFormElement 类型。HTMLFormElement 继承了 HTMLElement,因而与其他 HTML 元素具有相同的默认属性。不过,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 特性。
获取`<form>`元素:可以通过为其添加 id 值然后使用 getElementById()来获取;也可以通过 document.forms 取得页面中所有的表单的集合,然后通过数值索引或 name 值来取得特定的表单,如下:
```
var firstForm = document.forms[0]
var myForm = document.forms['form2']
```
另外,可以同时为表单指定 id 和 name,它们的值不一定相同。
## 提交表单
1.通过表单中的提交按钮提交
只要<span style="color: red">表单中存在</span>下面列出的任何一种按钮,那么在相应表单控件拥有焦点的情况下,按回车键就可以提交该表单。(textarea 是一个例外,在文本区中回车会换行。)如果表单里没有提交按钮,按回车键不会提交表单。
```html
<!-- 通用提交按钮 -->
<input type="submit" value="Submit Form">
<!-- 自定义提交按钮 -->
<button type="submit">Submit Form</button>
<!-- 图像按钮 -->
<input type="image" src="graphic.gif">
```
以这种方式提交表单时,浏览器会在将<span style="color: red">请求发送给服务器之前</span>触发 submit 事件。这样,我们就有机会验证表单数据,并据以决定是否允许表单提交。阻止这个事件的默认行为就可以取消表单提交。例如,下列代码会阻止表单提交
```
var form = document.getElementById('myForm')
form.addEventListener('submit', function (event) {
event = event ? event : window.event
event.preventDefault()
})
```
2.显式调用 submit() 方法:
```
var form = document.getElementById('myForm')
form.submit() // 提交表单
```
在以调用 submit() 方法的形式提交表单时,不会触发 submit 事件,因此要记得在调用此方法之前先验证表单数据
> 提交表单时可能出现的最大问题,就是重复提交表单。在第一次提交表单后,如果长时间没有反应,用户可能会变得不耐烦。这时候,他们也许会反复单击提交按钮。结果往往很麻烦(因为服务器要处理重复的请求),或者会造成错误(如果用户是下订单,那么可能会多订好几份)。解决这一问题的办法有两个:在第一次提交表单后就禁用提交按钮,或者利用 onsubmit 事件处理程序取消后续的表单提交操作。
## 重置表单
使用 type 特性值为"reset"的`<input>`或`<button>`都可以创建重置按钮,如下面的例子所示:
```html
<!-- 通用重置按钮 -->
<input type="reset" value="Reset Form">
<!-- 自定义重置按钮 -->
<button type="reset">Reset Form</button>
```
这两个按钮都可以用来重置表单。在重置表单时,所有表单字段都会恢复到页面刚加载完毕时的初始值。如果某个字段的初始值为空,就会恢复为空;<span style="color: red">而带有默认值的字段,也会恢复为默认值。</span>用户单击重置按钮重置表单时,会触发 reset 事件。
与 submit 一样,也可以通过 JavaScript 来重置表单 :`form.reset()`,其不同之处在于,调用 reset() 方法也会像单击重置按钮一样触发 reset 事件。
## 表单字段
每个表单都有 elements 属性,该属性是表单中所有表单元素(字段)的集合。这个 elements 集合是一个有序列表,其中包含着表单中的所有字段,例如`<input>`、`<textarea>`、`<button>`和`<fieldset>`。每个表单字段在 elements 集合中的顺序,与它们出现在标记中的顺序相同,可以按照位置和 name 特性来访问它们。下面来看一个例子:
```
var form = document.getElementById("form1")
// 取得表单中的第一个字段
var field1 = form.elements[0]
// 取得名为"textbox1"的字段
var field2 = form.elements["textbox1"]
// 取得表单中包含的字段的数量
var fieldCount = form.elements.length
```
如果有多个表单控件都在使用一个 name(如单选按钮),那么就会返回以该 name 命名的一个 NodeList
### 表单字段共有的属性、方法、事件
*****
**表单字段共有的属性如下:**
- disabled:布尔值,表示当前字段是否被禁用。
- form:指向当前字段所属表单的指针;只读。
- name:当前字段的名称。
- readOnly:布尔值,表示当前字段是否只读。
- tabIndex:表示当前字段的切换(tab)序号。
- type:当前字段的类型,如"checkbox"、"radio",等等。
- value:当前字段将被提交给服务器的值。对<u>文件字段</u>来说,这个属性是只读的,包含着文件在计算机中的路径。
**表单字段共有的方法:**
每个表单字段都有两个方法:focus() 和 blur()。其中,focus() 方法用于将浏览器的焦点设置到表单字段,即激活表单字段,使其可以响应键盘事件。接收到焦点的文本框会显示插入符号, 随时可以接收输入。例如:侦听页面的 load 事件,并在该事件发生时在表单的第一个字段上调用 focus() 方法
```
window.addEventListener('load', function (event) {
document.forms[0].elements[0].focus()
})
```
HTML5 为表单字段新增了一个 autofocus 属性。在支持这个属性的浏览器中,只要设置这个属性, 不用 JavaScript 就能自动把焦点移动到相应字段。例如:
```html
<input type="text" autofocus>
```
> 在默认情况下,只有表单字段可以获得焦点。对于其他元素而言,如果先将其 tabIndex 属性设置为 -1,然后再调用 focus()方法,也可以让这些元素获得焦点。
**表单字段共有的事件:**
除了支持鼠标、键盘、更改和 HTML 事件之外,所有表单字段都支持下列 3 个事件:
- blur:当前字段失去焦点时触发。
- change:对于`<input>`和`<textarea>`元素,在它们失去焦点且 value 值改变时触发;对于`<select>`元素,在其选项改变时触发。
- focus:当前字段获得焦点时触发。
需要区别的是,对于`<input>`元素,其 change 事件在失去焦点时才触发,而 input 事件在元素值发生改变时触发(如 Vue 的 v-model 指定绑定的就是 input 事件)
# 文本框脚本
在 HTML 中,有两种方式来表现文本框:一种是使用`<input>`元素的单行文本框,另一种是使用`<textarea>`的多行文本框。这两个控件非常相似,而且多数时候的行为也差不多。不过,它们之间仍然存在一些重要的区别。
要表现文本框,必须将`<input>`元素的 type 特性设置为"text"。而通过设置 size 特性,可以指定文本框中能够显示的字符数。通过 value 特性,可以设置文本框的初始值,而 maxlength 特性则用于指定文本框可以接受的最大字符数。如果要创建一个文本框,让它能够显示 25 个字符,但输入不能超过 50 个字符,可以使用以下代码:
```html
<input type="text" size="25" maxlength="50" value="initial value">
```
相对而言,`<textarea>`元素则始终会呈现为一个多行文本框。要指定文本框的大小,可以使用 rows 和 cols 特性。其中,rows 特性指定的是文本框的字符行数,而 cols 特性指定的是文本框的字符列数(类似于`<input>`元素的 size 特性)。与`<input>`元素不同,`<textarea>`的初始值必须要放在`<textarea>`和`</textarea>`之间,如下面的例子所示:
```html
<textarea rows="25" cols="5">initial value</textarea>
```
不能在 HTML 中指定 textarea 的最大字符数。
## 屏蔽特定字符
如果想屏蔽特定的字符,需要检测 keypress 事件对应的字符编码,然后再决定如何响应。例如,下列代码只允许用户输入数值:
```
textbox.addEventListener('keypress', function (event) {
event = event || window.event
var target = event.target
var charCode = event.charCode
// 另外还要确保用户没有按下 Ctrl 键
if (!/\d/.test(String.fromCharCode(charCode)) && event.ctrlKey) {
event.preventDefault() // 屏蔽按键事件
}
})
```
## 操作剪贴板
下列就是 6 个剪贴板事件:
- beforecopy:在发生复制操作前触发。
- copy:在发生复制操作时触发。
- beforecut:在发生剪切操作前触发。
- cut:在发生剪切操作时触发。
- beforepaste:在发生粘贴操作前触发。
- paste:在发生粘贴操作时触发。
可以使用 clipboardData 对象访问剪贴板中的数据,clipboardData 对象有三个方法:getData()、setData() 和 clearData()
>[warning] 操作剪贴板的不同浏览器的实现方式不同,暂不深入
## 自动切换焦点
所谓自动切换焦点即用户填写完当前字段自动将焦点切换到下一个字段,通常需要借助 maxlength 属性来确定用户是否输入了既定长度的字数
```html
<form>
<input type="text" name="tel1" id="txtTel1" maxlength="3">
<input type="text" name="tel2" id="txtTel2" maxlength="3">
<input type="text" name="tel3" id="txtTel3" maxlength="4">
</form>
```
```js
(function () {
function tabForward(event) {
event = event || window.event
let target = event.target // 触发事件的元素
if (target.value.length === target.maxLength) {
let form = target.form // 可以获取包裹这个表单字段的 form 元素
for (let i = 0, len = form.elements.length; i < len; i++) { // 通过 form 的 elements 属性获取表单字段
if (form.elements[i] === target) {
if (form.elements[i + 1]) {
form.elements[i + 1].focus()
}
return
}
}
}
}
let textbox1 = document.getElementById('txtTel1')
let textbox2 = document.getElementById('txtTel2')
let textbox3 = document.getElementById('txtTel3')
textbox1.addEventListener('keyup', tabForward) // 松开键盘后触发
textbox2.addEventListener('keyup', tabForward)
textbox3.addEventListener('keyup', tabForward)
})()
```
# HTML5 约束验证 API
1、必填字段:`required`属性,任何标注有 required 属性的字段,在提交表单时都不能空着。
```html
<input type="text" name="username" required>
```
在 JavaScript 中,通过对应的 required 属性,可以检查某个表单字段是否为必填字段。
```js
var isUsernameRequired = document.forms[0].elements["username"].required
```
另外,使用下面这行代码可以测试浏览器是否支持 required 属性。
```js
var isRequiredSupported = "required" in document.createElement("input") // 通过特性检测来确定新创建的元素中是否存在 required 属性
```
> 对于空着的必填字段,不同浏览器有不同的处理方式。Firefox 4 和 Opera 11 会阻止表单提交并在相 应字段下方弹出帮助框,而 Safari(5 之前)和 Chrome(9 之前)则什么也不做,而且也不阻止表单提交
![](https://box.kancloud.cn/d06197f21e6fa6dfce462f06b1b4c2b2_1575x549.png)
2、其他输入类型:HTML5 为 `<input>` 的 type 属性增加了新的几个值,这些新的类型不仅能反应数据类型的信息,还能提供一些默认的验证功能,其中 "email" 和 "url" 是得到支持最多的类型,各浏览器也都为其增加了定制的验证机制。
3、数值范围:"number"、"range"、"datetime"、"datetime-local"、"date"、"month"、"week"、"time" 这些属性要求填写某种基于数字的值
例如,想让用户只能输入 0 到 100 的值,而且这个值必须是 5 的倍数,可以这样写代码:
```html
<input type="number" min="0" max="100" step="5" name="count">
```
4、输入模式:HTML5 为文本字段新增了 pattern 属性。这个属性的值是一个正则表达式,用于匹配文本框中的值。例如,如果只想允许在文本字段中输入数值,可以像下面的代码一样应用约束:
```html
<input type="text" pattern="\d+" name="count">
```
注意,模式的开头和末尾不用加`^`和`$`符号(假定已经有了)。这两个符号表示输入的值必须从头到尾都与模式匹配。
5、检测有效性:使用 `checkValidity()`方法可以检测表单中的某个字段是否有效。所有表单字段都有这个方法,如果字段的值有效,这个方法返回 true,否则返回 false。字段的值是否有效的判断依据是本节前面介绍过的那些约束。换句话说,必填字段中如果没有值就是无效的,而字段中的值与 pattern 属性不匹配也是无效的。例如:
```js
if (document.forms[0].elements[0].checkValidity()){
// 字段有效,继续
} else {
// 字段无效
}
```
要检测整个表单是否有效,可以在表单自身调用`checkValidity()`方法。如果所有表单字段都有效,这个方法返回 true;即使有一个字段无效,这个方法也会返回 false。
```js
if(document.forms[0].checkValidity()){
// 表单有效,继续
} else {
// 表单无效
}
```
# 富文本编辑
推荐阅读:[利用 javaScript 实现副本文编辑器 | 百度EUX](http://eux.baidu.com/blog/fe/%E5%88%A9%E7%94%A8-javascript-%E5%AE%9E%E7%8E%B0%E5%AF%8C%E6%96%87%E6%9C%AC%E7%BC%96%E8%BE%91%E5%99%A8)
## 使用 contenteditable 属性
可以把 contenteditable 属性应用给页面中的任何元素,然后用户立即就可以编辑该元素
```html
<div class="editable" id="richedit" contenteditable></div>
```
这样,元素中包含的任何文本内容就都可以编辑了,就好像这个元素变成了`<textarea>`元素一样。通过在这个元素上设置 contenteditable 属性,也能打开或关闭编辑模式
```js
var div = document.getElementById("richedit")
div.contentEditable = "true";
```
## 操作富文本
与富文本编辑器交互的主要方式,就是使用 document.execCommand()。这个方法可以对文档执行预定义的命令,而且可以应用大多数格式。可以为 document.execCommand()方法传递 3 个参数:
- 要执行的命令名称
- 表示浏览器是否应该为当前命令提供用户界面的一个布尔值
- 执行命令必须的一个值(如果不需要值,则传递 null)。
为了确保跨浏览器的兼容性,第二个参数应该始终设置为 false,因为 Firefox 会在该参数为 true 时抛出错误。不同浏览器支持的预定义命令也不一样。下表列出了那些被支持最多的命令。
|命 令 |值(第三个参数)| 说 明|
| --- | --- | --- |
|backcolor |颜色字符串 |设置文档的背景颜色|
|bold |null |将选择的文本转换为粗体|
|copy| null| 将选择的文本复制到剪贴板|
|createlink |URL字符串| 将选择的文本转换成一个链接,指向指定的URL|
|cut |null| 将选择的文本剪切到剪贴板|
|delete |null |删除选择的文本|
|fontname| 字体名称| 将选择的文本修改为指定字体|
|fontsize| 1~7 |将选择的文本修改为指定字体大小|
|forecolor| 颜色字符串| 将选择的文本修改为指定的颜色|
|formatblock| 要包围当前文本块的HTML标签;如`<h1>`|使用指定的HTML标签来格式化选择的文本块
|indent| null |缩进文本|
|inserthorizontalrule |null |在插入字符处插入一个`<hr>`元素|
|insertimage| 图像的URL |在插入字符处插入一个图像|
|insertorderedlist |null |在插入字符处插入一个`<ol>`元素|
|insertunorderedlist |null| 在插入字符处插入一个`<ul>`元素|
|insertparagraph| null |在插入字符处插入一个`<p>`元素|
|italic |null |将选择的文本转换成斜体|
|justifycenter| null |将插入光标所在文本块居中对齐|
|justifyleft| null| 将插入光标所在文本块左对齐|
|outdent| null |凸排文本(减少缩进)|
|paste| null| 将剪贴板中的文本粘贴到选择的文本|
|removeformat| null |移除插入光标所在文本块的块级格式。这是撤销formatblock命令的操作|
|selectall |null| 选择文档中的所有文本|
|underline |null |为选择的文本添加下划线|
|unlink |null |移除文本的链接。这是撤销createlink命令的操作|
其中,与剪贴板有关的命令在不同浏览器中的差异极大。Opera 根本没有实现任何剪贴板命令,而Firefox 在默认情况下会禁用它们(必须修改用户的首选项来启用它们)。Safari 和 Chrome 实现了 cut 和 copy,但没有实现 paste。不过,即使不能通过 document.execCommand()来执行这些命令,但却可以通过相应的快捷键来实现同样的操作。可以在任何时候使用这些命令来修改富文本区域的外观,如下面的例子所示。
```js
// 转换粗体文本
document.execCommand("bold", false, null)
// 转换斜体文本
document.execCommand("italic", false, null)
// 创建指向 www.wrox.com 的链接
document.execCommand("createlink", false,"http://www.wrox.com")
// 格式化为 1 级标题
document.execCommand("formatblock", false, "<h1>")
```
- 序言 & 更新日志
- H5
- Canvas
- 序言
- Part1-直线、矩形、多边形
- Part2-曲线图形
- Part3-线条操作
- Part4-文本操作
- Part5-图像操作
- Part6-变形操作
- Part7-像素操作
- Part8-渐变与阴影
- Part9-路径与状态
- Part10-物理动画
- Part11-边界检测
- Part12-碰撞检测
- Part13-用户交互
- Part14-高级动画
- CSS
- SCSS
- codePen
- 速查表
- 面试题
- 《CSS Secrets》
- SVG
- 移动端适配
- 滤镜(filter)的使用
- JS
- 基础概念
- 作用域、作用域链、闭包
- this
- 原型与继承
- 数组、字符串、Map、Set方法整理
- 垃圾回收机制
- DOM
- BOM
- 事件循环
- 严格模式
- 正则表达式
- ES6部分
- 设计模式
- AJAX
- 模块化
- 读冴羽博客笔记
- 第一部分总结-深入JS系列
- 第二部分总结-专题系列
- 第三部分总结-ES6系列
- 网络请求中的数据类型
- 事件
- 表单
- 函数式编程
- Tips
- JS-Coding
- Framework
- Vue
- 书写规范
- 基础
- vue-router & vuex
- 深入浅出 Vue
- 响应式原理及其他
- new Vue 发生了什么
- 组件化
- 编译流程
- Vue Router
- Vuex
- 前端路由的简单实现
- React
- 基础
- 书写规范
- Redux & react-router
- immutable.js
- CSS 管理
- React 16新特性-Fiber 与 Hook
- 《深入浅出React和Redux》笔记
- 前半部分
- 后半部分
- react-transition-group
- Vue 与 React 的对比
- 工程化与架构
- Hybird
- React Native
- 新手上路
- 内置组件
- 常用插件
- 问题记录
- Echarts
- 基础
- Electron
- 序言
- 配置 Electron 开发环境 & 基础概念
- React + TypeScript 仿 Antd
- TypeScript 基础
- 样式设计
- 组件测试
- 图标解决方案
- Algorithm
- 排序算法及常见问题
- 剑指 offer
- 动态规划
- DataStruct
- 概述
- 树
- 链表
- Network
- Performance
- Webpack
- PWA
- Browser
- Safety
- 微信小程序
- mpvue 课程实战记录
- 服务器
- 操作系统基础知识
- Linux
- Nginx
- redis
- node.js
- 基础及原生模块
- express框架
- node.js操作数据库
- 《深入浅出 node.js》笔记
- 前半部分
- 后半部分
- 数据库
- SQL
- 面试题收集
- 智力题
- 面试题精选1
- 面试题精选2
- 问答篇
- Other
- markdown 书写
- Git
- LaTex 常用命令