Skip to content

Latest commit

 

History

History
348 lines (232 loc) · 12.7 KB

第14章-表单脚本.md

File metadata and controls

348 lines (232 loc) · 12.7 KB

表单脚本

目标:

  1. 理解表单
  2. 文本框验证和交互
  3. 使用其他表单控制

14.1 表单基础知识

在HTML中,表单是由

元素来表示的,而在JavaScript中,表单对应的元素类型是HTMLFormElement类型,HTMLFormElement继承了HTMLElement,所以除了与其他html元素具有的相同属性之外还拥有以下属性。

  1. acceptCharset: 服务器能够处理的字符集,等价于HTML中的accept-charset。

  2. action: 接受请求的URL,等价于html中的action特性

  3. enctype: 请求的编码类型,等价于html中的enctype

  4. length:表单中控件的数量

  5. method: 要发送的http请求的类型,通常是get或者post,等价于html中的method特性

  6. name:表单的名称,等价于html中的name属性

  7. reset(): 将表单域重置为默认值

  8. submit(): 提交表单

  9. target: 用于发送请求和接收响应的窗口的名称,等价于html中的target属性。

获取表单引用的一些方式

  1. 通过getElementById方法找到

  2. 通过document.forms可以获取到页面中所有的表单,并通过索引或者name取得特定的表单。

let forms = document.forms
let firstForm = forms[0]
let myForm = form['form2']

14.1.1 提交表单

用户点击提交按钮或者图像按钮就会提交表单。使用或者都可以定义提交按钮,只要将其type类型的值设置为‘submit’即可。图像按钮则是将的type设置为‘image’。

只要表单中存在上面列出的任何一种按钮,那么在相应的表单控件拥有焦点的情况下,按下回车键就可以提交表单(需要注意的是textarea是个例外,会换行。),相反没有以上的提交按钮,则不会提交表单

以以上三种按钮提交表单的时候,浏览器在将请求发送给服务器前触发submit事件,这样我们就有机会可以验证表单数据,并决定是不是允许表单提交

<form action="https://github.com/">
  <input type="text" value="用户名" name="username">
  <input type="password" value="pwd" name="password">
  <input type="submit" value="提交表单"> 
</form>
let $form = document.forms[0]
let fields = [].slice.call($form.elements)
let checkForm = () => {
  return (fields.filter((ele) => {
    return ['text', 'password'].includes(ele.type)
  }).every((ele) => {
    return ele.value.length > 6
  }))
}

$form.addEventListener('submit', function (event) {
  if (checkForm()) {
    // xxx 通过表单验证
  } else {
    // xxx 没通过
    event.preventDefault()
  }
}, false)

14.1.2 重置表单

和表单提交有类似,可以通过<input>或者button标签并且type属性为reset来创建重置按钮。它的功能就是将所有的表单字段都恢复到页面刚加载完毕的时候的初始值。同样用户点击充值表单的时候会触发reset事件,我们可以必要的时候取消重置操作

<form action="https://github.com/">
  <input type="text" value="用户名" name="username">
  <input type="password" value="pwd" name="password">
  <!-- 以下两种方式都可以定义重置按钮 -->
   <input type="reset" value="重置表单">  
  <!-- <button>重置表单</button>   -->
</form>

稍微修改一下上面的脚本

let $form = document.forms[0]
  let fields = [].slice.call($form.elements)
  let checkForm = () => {
    return (fields.filter((ele) => {
      return ['text', 'password'].includes(ele.type)
    }).every((ele) => {
      return ele.value.length > 6
    }))
  }

  ['submit', 'reset'].forEach((v) => {
    $form.addEventListener(v, function (event) {
      if (checkForm()) {
        // xxx 通过表单验证
      } else {
        // xxx 没通过
        event.preventDefault()
      }
    }, false)
  })

**当然最后我们也可以通过form.reset()**在js中手动触发重置操作。

14.1.3 表单字段

表单元素与其他的原生元素一样,可以使用getElementById等方式去访问。此外每个表单都有一个elements属性,表示表单中所有元素的集合。如果有多个表单控件都在使用一个name(比如单选按钮),name就会返回以该name命名的一个NodeList

 <form action="">
  <input type="text" name="username">
  <input type="text" name="username">
  <input type="text" name="pwd">
  <input type="radio" name="sex" value="boy">
  <input type="radio" name="sex" value="girl">
  <input type="submit">
</form>
let $form = document.forms[0]
let elements = $form.elements

以下是elements变量的取值,可以看到可以通过索引0,1,2等形式去访问表单控件,也可以通过pwd,sex等命名形式去访问。

共有的表单字段属性

除了

元素之外,所有的表单字段都拥有相同的一组属性。比如如下。

  1. disabled:布尔值,表示当前字段是否被禁用。
  2. form:指向当前字段所属表单的指针,只读。
  3. name:当前字段的名称
  4. readOnly:布尔值,表示当前字段是否只读。
  5. tabIndex:表示当前字段的切换号
  6. type:当前字段的类型,如“checkbox”,“radio”等等
  7. value:当前字段被提交给服务器的值,对文件字段来说,这个属性是只读的,包含着文件在计算机中的路径。

除了form属性之外,可以通过js动态修改其值

共有的表单字段方法

  1. focus(),获取焦点
  2. blur(),失去焦点

需要注意的是,只有表单字段才可以获取焦点,对于其他元素来说,如果先将其tabIndex属性设置为-1,然后在调用focus()方法,也可以让这些元素获得焦点。当前opera目前不支持这种技术

共有的表单事件

除了支持鼠标,键盘,更改和HTML事件之外,所有表单字段都支持下面三个事件。

  1. blur:当前子弹失去焦点时触发
  2. change:对于input和textarea元素来说,在他们是去焦点并且值改变时触发,对于select元素,在其选项改变时触发,
  3. focus:当前字段获得焦点时触发

14.2 文本框脚本

在HTML中,元素和<textarea>元素都表示文本框。这两个空间非常类似,而且大多数的时候行为也差不多,不过还是有一些差别。

  1. 对于input元素来说可以通过size特性来设置能够显示的字符数,通过value特性,可以设置初始值。,而maxlength则可以指定能够接受的最大字符数。如果要创建一个文本框,让他能够显示25个字符,单输入不能超过50个字符。可以用如下代码。
<input type="text" size="25" maxlength="50" value="initial value">
  1. 但是对于<textarea>而言,元素始终会呈现为一个多行文本,要指定文本框的大小可以通过rowscols,rows表示行数,cols表示列数。与元素的区别在于其初始值需要放在<textarea>initial value<textarea>之间。并且不能指定最大字符数。

14.2.1 选择文本

上述两种文本框都支持select()方法,这个方法用于选择文本框中的所有文本,在调用select()方法时,大多数浏览器都会讲焦点设置到文本框中。

在文本框获取焦点时选择所有文本,可以让用户不必一个一个删除文本。

  1. select事件

select()方法对应的是select事件,在选择了文本框的文本时就会触发select事件。但是什么时候触发会因浏览器而异。在ie9+,Opera,FireFox,Chrome和Safari中,只有用户选择了文本而且释放了鼠标才会触发select事件。但是在ie8及更早的版本中只要用户选择了一个字母,不必释放鼠标,就会触发。当然在调用select()方法的时候也会触发该事件。

  1. 获取选择的文本

通过selectionStartselectionEnd表示所选择的文本的范文(即文本选区的开头和结尾的偏移量),就可以知道用户到底选择了啥。

$area.addEventListener('select', (e) => {
  console.log($area.value.substring($area.selectionStart, $area.selectionEnd))
}, false)

当然该方式是有兼容问题的,

  1. 选择部分文本

HTML5中为选择文本框中的部分文本提供了解决方法,即setSelectionRange方法,接收两个参数,要选择地第一个和最后一个字符之后的字符的索引。

14.2.2 过滤输入

我们经常会要求用户在文本框中输入特定格式的数据,比如必须匹配某种模式,我们可以综合运用事件和DOM手段,来将普通的文本框转化成能够理解用户输入数据的功能控件。

  1. 屏蔽字符

有时候我们需要用户输入的文本中不包含某些字符,这个时候可以给keypress事件,阻止这个事件的默认行为来屏蔽此类字符。甚至在某些极端的情况下可以屏蔽掉所有操作。

$keyPress.addEventListener('keypress', (e) => {
  e.preventDefault()
}, false)
  1. 操作剪切板

IE是第一个支持与剪切板相关事件,以及通过js访问剪切板数据的浏览器。后来html5也把剪切板事件纳入了规范,下面是6个剪切板事件。

  1. beforecopy: 在发生复制操作前触发
  2. copy:在发生复制操作时触发
  3. beforecut:在发生剪切操作前触发
  4. cut:在发生剪切操作时触发
  5. beforepaste:在发生粘贴操作前触发
  6. paste:在发生粘贴操作时触发
<div class="box">
  <input type="text" class="paste-input">
</div>
let $pasteInput = document.querySelector('.paste-input')

let getClipboardData = (e) => {
  let clipboardData = (e || event).clipboardData

  return clipboardData.getData('text')
}
let setClipboardData = (e, val) => {
  let params = e.clipboardData ? 'text/plain' : 'text'
  let clipboardData = (e || event).clipboardData

  clipboardData.setData(params, val)
}

$pasteInput.addEventListener('paste', (e) => {
  let data = getClipboardData(e)
  console.log('paste===', data)
}, false)

拿到的兼容事件对象上有一个clipboardData属性,这个对象有三个方法,分别是getData,setData和clearData。用于从剪切板中取得数据,他接收一个参数,即要取得的数据的格式,在ie中,有两种数据格式:‘text’和‘url’,在firefox和safari中的setData方法不能识别‘text’类型,这两个浏览器在成功将文本放到剪切板中后,都会返回true,否则返回false

14.2.3 自动切换焦点

使用js可以从多个方面增强表单的易用性,其中,最常见的一种方式就是在用户填写完当前字段的时候,自动将焦点切换到下一个字段。通常在自动切换焦点之前,必须知道用户已经输入了既定的长度的数据(比如电话号码)。

<form action="" name="form1">
  <input type="text" name="tel1" maxlength="3">
  <input type="text" name="tel2" maxlength="4">
  <input type="text" name="tel3" maxlength="5">
</form>
let $form = document.forms['form1']

let getNextInput = (e) => {
  let target = (e || event).target
  let maxLength = target.maxLength
  let val = target.value
  let name = target.name
  let len = name.length
  let nextInputIndex = Number(name[name.length - 1]) + 1
  let prefix

  if (val.length === maxLength) {
    prefix = name.slice(0, len - 1)
    name = `${prefix}${nextInputIndex}`
    return $form.elements[name]
  }
}


$form.addEventListener('keyup', (e) => {
  let $nextInput = getNextInput(e)
  
  if ($nextInput) {
    $nextInput.focus()
  }
}, false)

14.4 表单序列化

在浏览器中提交表单之前,浏览器是怎样将数据发送给服务器的,如下说明。

  1. 对表单字段的名称和值进行URL(encodeURIComponent())编码,并使用(&)进行分割
  2. 不发送禁用的表单字段
  3. 只发送勾选的复选框和单选按钮
  4. 不发送type为resetbutton的按钮
  5. 多选框中每个选中的值单独一个条目
  6. 在单击提交按钮提交表单的情况下,也会发送提交按钮;否则不会发送,也包括type为image的input元素
  7. <select>元素的值就是选中的 <option>元素的value值,如果<option>元素没有value�特性则是<option>的文本值

放一张常见的表单提交的GET方式各个字段的截图

放一张常见的表单提交的POST方式各个字段的截图

放一张常见的表单提交的POST方式各个字段的截图

放一张常见的表单提交的POST方式各个字段的截图

有以上知识点即可以回到第21章�继续Ajax相关