Form表单相关知识整理

我心飞翔 分类:javascript

表单概述

表单(<form>)用来收集用户提交的数据,发送到服务器。

常见的表单是登陆界面,用户提交用户名和密码,让服务器验证。

  <form action="/handling-page" method="post">
    <div>
      <label>用户名:
        <input type="text" id="name" name="user_name" />
      </label>
    </div>
    <div>
      <label>密码:
        <input type="password" id="passwd" name="user_passwd" />
      </label>
    </div>
    <div>
      <input type="submit" id="submit" name="submit_button" value="提交" />
    </div>
  </form>
 

image.png

上面代码就是一个简单的表单,包含三个控件:用户名输入框、密码输入框和提交按钮。

用户点击“提交”按钮,每一个控件都会生成一个键值对,键名是控件的name属性,键值是控件的value属性,键名和键值之间由等号连接。比如,用户名输入框的name属性是user_name,value属性是用户输入的值,假定是“张三”,提交到服务器的时候,就会生成一个键值对user_name=张三。

表单基础

在 JS 中表单的类型以 HTMLFormElement 表示。这个类型继承自 HTMLElement。

除了平常获取元素的方法比如 querySelector 、getElementById 外,还可以使用 document.forms 来获取到页面的所有表单元素。

<form name="myForm">
</form>
<form name="myForm2">
 

获得的是这样的表单结果
image.png

所以我们可以使用索引来获取对应的表单元素。

document.forms['myForm2'] //获取名字为myForm2的表单元素
docoment.form[0] //获得第一个表单
 

method

所有的键值对都会提交到服务器。但是,提交的数据格式跟<form>元素的method属性有关。该属性指定了提交数据的 HTTP 方法。如果是 GET 方法,所有键值对会以 URL 的查询字符串形式,提交到服务器,比如/handling-page?user_name=张三&user_passwd=123&submit_button=提交。下面就是 GET 请求的 HTTP 头信息。

GET /handling-page?user_name=张三&user_passwd=123&submit_button=提交
Host: example.com
 

如果是post方法,那么数据就会作为请求体发送给服务器。所有键值对会连接成一行。下面就是 POST 请求的头信息。

POST /handling-page HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 74

user_name=张三&user_passwd=123&submit_button=提交
 

但是实际提交的时候,只要键值不是 URL 的合法字符,比如上面的汉字张三和提交,那么浏览器会自动进行编码后发送给服务器。

提交方法

在表单中采用type=submit的控件,就可以提交表单。

    <form>
      <input type="submit" value="提交" />
    </form>
 

一般我们会采用button标签,直接放在form中,这样也可以提交表单。button的默认type为submit

    <form>
      <button>提交<button>
    </form>
 

除此之外,我们还可以实用表单元素的submit方法,通过js提交表单。

document.querySelector('form').submit()
 

submit方法是来自于HTMLFormElement这个对象,而实例form元素是通过继承HTMLFormElement才得以调用。

通过reset方法可以重置所有表单的value值

document.querySelector('form').reset()
 

提交表单细节

上面说到在表单内有 button 控件或者有 type 为 submit 的 input 控件都可以提交表单,除此之外还有 type 为 image 的input 控件也可以用来提交表单。

<input type='image' src='xxx.jpg'/>
 

如果焦点在上述三种表单控件上,那么按回车键也会触发表单提交。如果没有提交按钮,那表单即使按回车键也不会触发提交按钮。

当用上面方式提交表单时,会触发一个 submit 事件,我们可以在这时候验证一下表单数据。如果此时阻止默认行为,那么就可以取消提交。

let form =document.getElementById('myform')
form.addEvemtListener('submit',(e)=>{
  e.preventDefault()//取消提交
})
 

如果采用 submit()方法提交的话,则无需表单控件,直接 js 脚本触发,但是这个方法并不会触发 submit 事件,因此应当先进行表单验证后触发 submit 方法。

提交表单时用户可能会触发二次提交,目前已经比较好的方法是提交完之后给表单设置禁用属性,或者监听 onsubmit 事件来取消之后的表单提交。

重置表单

除了使用reset 方法重置表单外,还可以采用 type 值为 reset 的 input 控件或者 button 控件来重置表单。

<input type='reset' value='reset form'/>
<button type='reset'>reset form</button>
 

不管是 reset 方法还是上述两个控件,在重置表单后都会触发 reset 事件,同样的,我们可以禁止默认行为来阻止表单重置

let form =document.getElementById('myform')
form.addEvemtListener('reset',(e)=>{
  e.preventDefault()//取消提交
})
 

FormData 对象

表单数据以键值对的形式向服务器发送,这是由浏览器自动完成的。但是有时候,我们需要自己通过 js 来完成,构造一个表单并发送给服务器。这就需要用到 formData 对象

formData 是一个构造函数,用来生成表单的实例

var formData = new FormData(form)
 

FormData构造函数可接收一个 DOM 的表单元素作为参数,它会自动处理表单的键值对。这个参数是可选的,如果省略,就表示一个空的表单。

new FormData() //一个空表单
 

如果接收一个表单元素,那么就可以获得表单元素的键值对。

我们可以利用 FormData 来处理上面的表单。

FormData提供以下方法

  • FormData.get(key):获取指定键名对应的键值,参数为键名。如果有多个同名的键值对,则返回第一个键值对的键值。
  • FormData.getAll(key):返回一个数组,表示指定键名对应的所有键值。如果有多个同名的键值对,数组会包含所有的键值。
  • FormData.set(key, value):设置指定键名的键值,参数为键名。如果键名不存在,会添加这个键值对,否则会更新指定键名的键值。如果第二个参数是文件,还可以使用第三个参数,表示文件名。
  • FormData.delete(key):删除一个键值对,参数为键名。
  • FormData.append(key, value):添加一个键值对。如果键名重复,则会生成两个相同键名的键值对。如果第二个参数是文件,还可以使用第三个参数,表示文件名。
  • FormData.has(key):返回一个布尔值,表示是否具有该键名的键值对。
  • FormData.keys():返回一个遍历器对象,用于for...of循环遍历所有的键名。
  • FormData.values():返回一个遍历器对象,用于for...of循环遍历所有的键值。
  • FormData.entries():返回一个遍历器对象,用于for...of循环遍历所有的键值对。如果直接用for...of循环遍历 FormData 实例,默认就会调用这个方法。

下面是遍历器的例子

表单验证

表单自身有 API 可以指定一些条件,自动进行验证。

如果一个控件通过验证,它就会匹配:valid的 CSS 伪类,浏览器会继续进行表单提交的流程。如果没有通过验证,该控件就会匹配:invalid的 CSS 伪类,浏览器会终止表单提交,并显示一个错误信息。

checkValidity()

这个方法用来手动触发表单校验,表单元素和表单控件都有checkValidity()这个方法。

这个方法返回一个布尔值,true 代表通过,false 表示失败。

willValidate 属性

控件元素的willValidate属性是一个布尔值,表示该控件是否会在提交时进行校验。

validationMessag属性

控件元素的validationMessage属性返回一个字符串,表示控件不满足校验条件时,浏览器显示的提示文本。以下两种情况,该属性返回空字符串。

  • 该控件不会在提交时自动校验
  • 该控件满足校验条件

下面是另一个例子

image.png

setCustomValidity()

那么如果我们想指定表单验证失败后的内容,就可以使用这个 API。还是上面的例子,我们修改一下

已经修改掉系统自带的提示文字了
image.png

上面的表单输入框,要求只能输入小写字母,且不得超过15个字符。如果输入不符合要求(比如输入“ABC”),提交表单的时候,Chrome 浏览器会弹出报错信息“Please match the requested format.”,禁止表单提交。下面使用setCustomValidity()方法替换掉报错信息。

上面代码中,setCustomValidity()方法是在invalid事件的监听函数里面调用。

该方法也可以直接调用,这时如果参数不为空字符串,浏览器就会认为该控件没有通过校验,就会立刻显示该方法设置的报错信息。

image.png

上面代码一旦发现文件大于 75KB,就会设置校验失败,同时给出自定义的报错信息。然后,点击提交按钮时,就会显示报错信息。这种校验失败是不会自动消除的,所以如果所有文件都符合条件,要将报错信息设为空字符串,手动消除校验失败的状态。

validity属性

控件元素的属性validity属性返回一个ValidityState对象,包含当前校验状态的信息。

该对象有以下属性,全部为只读属性。

  • ValidityState.badInput:布尔值,表示浏览器是否不能将用户的输入转换成正确的类型,比如用户在数值框里面输入字符串。
  • ValidityState.customError:布尔值,表示是否已经调用setCustomValidity()方法,将校验信息设置为一个非空字符串。
  • ValidityState.patternMismatch:布尔值,表示用户输入的值是否不满足模式的要求。
  • ValidityState.rangeOverflow:布尔值,表示用户输入的值是否大于最大范围。
  • ValidityState.rangeUnderflow:布尔值,表示用户输入的值是否小于最小范围。
  • ValidityState.stepMismatch:布尔值,表示用户输入的值不符合步长的设置(即不能被步长值整除)。
  • ValidityState.tooLong:布尔值,表示用户输入的字数超出了最长字数。
  • ValidityState.tooShort:布尔值,表示用户输入的字符少于最短字数。
  • ValidityState.typeMismatch:布尔值,表示用户填入的值不符合类型要求(主要是类型为 Email 或 URL 的情况)。
  • ValidityState.valid:布尔值,表示用户是否满足所有校验条件。
  • ValidityState.valueMissing:布尔值,表示用户没有填入必填的值。

如果想禁止浏览器弹出表单验证的报错信息,可以监听invalid事件。

上面代码中,一旦发生invalid事件(表单验证失败),event.preventDefault()用来禁止浏览器弹出默认的验证失败提示,然后设置定制的报错提示框。

表单的 novalidate 属性

表单元素的 HTML 属性novalidate,可以关闭浏览器的自动校验。

这个属性也可以在脚本里设置。

如果表单元素没有设置novalidate属性,那么提交按钮(<button><input>元素)的formnovalidate属性也有同样的作用。

enctype 属性

表单能够用四种编码,向服务器发送数据。编码格式由表单的enctype属性决定。

假定表单有两个字段,分别是foo和baz,其中foo字段的值等于bar,baz字段的值是一个分为两行的字符串。

下面四种格式,都可以将这个表单发送到服务器。

(1)GET 方法

如果表单使用GET方法发送数据,enctype属性无效。

数据将以 URL 的查询字符串发出。

(2)application/x-www-form-urlencoded

如果表单用POST方法发送数据,并省略enctype属性,那么数据以application/x-www-form-urlencoded格式发送(因为这是默认值)。

发送的 HTTP 请求如下。

上面代码中,数据体里面的%0D%0A代表换行符(\r\n)。

(3)text/plain

如果表单使用POST方法发送数据,enctype属性为text/plain,那么数据将以纯文本格式发送。

发送的 HTTP 请求如下。

(4)multipart/form-data

如果表单使用POST方法,enctype属性为multipart/form-data,那么数据将以混合的格式发送。

发送的 HTTP 请求如下。

这种格式也是文件上传的格式。

文件上传

用户上传文件,也是通过表单。用户通过文件输入框将本地文件,提交表单的时候,浏览器就会将这个文件发送到服务器上。

此外,还需要将表单<form>元素的method属性设为POST,enctype属性设为multipart/form-data。其中,enctype属性决定了 HTTP 头信息的Content-Type字段的值,默认情况下这个字段的值是application/x-www-form-urlencoded,但是文件上传的时候要改成multipart/form-data

上面的 HTML 代码中,file 控件的multiple属性,指定可以一次选择多个文件;如果没有这个属性,则一次只能选择一个文件。

然后,新建一个 FormData 实例对象,模拟发送到服务器的表单数据,把选中的文件添加到这个对象上面。

最后,使用 Ajax 向服务器上传文件。

除了发送 FormData 实例,也可以直接 AJAX 发送文件。

File对象

File 对象代表文件,用来读写文件信息。最常见的就是表单的上传控件,用户选中文件以后,浏览器就会生成一个数组,里面是每一个用户选中的文件,它们都是 File 实例对象。

上面代码中,file是用户选中的第一个文件,它是 File 的实例。

File 构造函数

我们也可以生成 File 实例对象

File()构造函数接受三个参数。

  • array:一个数组,成员可以是二进制对象或字符串,表示文件的内容。
  • name:字符串,表示文件名或文件路径。
  • options:配置对象,设置实例的属性。该参数可选。

第三个参数配置对象,可以设置两个属性。

  • type:字符串,表示实例对象的 MIME 类型,默认值为空字符串。
  • lastModified:时间戳,表示上次修改的时间,默认为Date.now()。

File 对象有以下实例属性。

  • File.lastModified:最后修改时间
  • File.name:文件名或文件路径
  • File.size:文件大小(单位字节)
  • File.type:文件的 MIME 类型

File 对象没有自己的实例方法,由于继承了 Blob 对象,因此可以使用 Blob 的实例方法slice()。

FileList 对象

FileList对象是一个类似数组的对象,代表一组选中的文件,每个成员都是一个 File 实例。它主要出现在两个场合。

  • 文件控件节点(<input type="file">)的files属性,返回一个 FileList 实例。
  • 拖拉一组文件时,目标区的DataTransfer.files属性,返回一个 FileList 实例。

上面代码中,文件控件的files属性是一个 FileList 实例。

FileList 的实例属性主要是length,表示包含多少个文件。

FileReader 对象

FileReader 对象用于读取 File 对象或 Blob 对象所包含的文件内容。

浏览器原生提供一个FileReader构造函数,用来生成 FileReader 实例。

FileReader 有以下的实例属性。

  • FileReader.error:读取文件时产生的错误对象
  • FileReader.readyState:整数,表示读取文件时的当前状态。一共有三种可能的状态,0表示尚未加载任何数据,1表示数据正在加载,2表示加载完成。
  • FileReader.result:读取完成后的文件内容,有可能是字符串,也可能是一个 ArrayBuffer 实例。
  • FileReader.onabort:abort事件(用户终止读取操作)的监听函数。
  • FileReader.onerror:error事件(读取错误)的监听函数。
  • FileReader.onload:load事件(读取操作完成)的监听函数,通常在这个函数里面使用result属性,拿到文件内容。
  • FileReader.onloadstart:loadstart事件(读取操作开始)的监听函数。
  • FileReader.onloadend:loadend事件(读取操作结束)的监听函数。
  • FileReader.onprogress:progress事件(读取操作进行中)的监听函数。

下面是监听load事件的一个例子。

上面代码中,每当文件控件发生变化,就尝试读取第一个文件。如果读取成功(load事件发生),就打印出文件内容。

FileReader 有以下实例方法。

  • FileReader.abort():终止读取操作,readyState属性将变成2。
  • FileReader.readAsArrayBuffer():以 ArrayBuffer 的格式读取文件,读取完成后result属性将返回一个 ArrayBuffer 实例。
  • FileReader.readAsBinaryString():读取完成后,result属性将返回原始的二进制字符串。
  • FileReader.readAsDataURL():读取完成后,result属性将返回一个 Data URL 格式(Base64 编码)的字符串,代表文件内容。对于图片文件,这个字符串可以用于<img>元素的src属性。注意,这个字符串不能直接进行 Base64 解码,必须把前缀data:/;base64,从字符串里删除以后,再进行解码。
  • FileReader.readAsText():读取完成后,result属性将返回文件内容的文本字符串。该方法的第一个参数是代表文件的 Blob 实例,第二个参数是可选的,表示文本编码,默认为 UTF-8。

下面是一个例子。

上面代码中,用户选中图片文件以后,脚本会自动读取文件内容,然后作为一个 Data URL 赋值给<img>元素的src属性,从而把图片展示出来。

表单事件

表单提交往往会有个默认刷新行为,一般我们都会使用e.preventDefault取消。

input事件

当input、select、texttarea的值发生变化时,就会触发input事件。它的特点是,操作一次就会触发一次。连续触发。

上面的代码,每一次对text进行修改,就会触发input事件,执行回调函数。

上面的select标签同理,每次选择不同的选项,也会触发input事件,可以说input是范围比较大的表单事件,包含的内容很多,而且特点是变化后立即发生。

input 事件跟 change 事件很像,不同之处是 input 事件是元素的值发生变化后立即发生,而 change 是在元素失去焦点后发生,React 的 onChange 事件并不是原生 change 事件,特别是在受控组件上,每次值发生变化都会触发。而 Vue 的 change 事件就跟原生事件一样。

那么总结 input 跟 change 原生事件的不同之处在于:

  • input 是每次值改变就会触发(连续的)
  • change 是失去焦点才触发,尽管值可能已经变化多次。

select事件

select是选中文本事件,当我们在input内选中文本时,会触发这个事件,可以通过e.target中的value属性拿到选中的文本

上面的代码直接打出了选中的文本。

选中的文本可以通过event.target元素的selectionDirectionselectionEndselectionStartvalue属性拿到。

change 事件

上面的input事件的特点我们已经知道了,虽然input事件非常好,但是有时候过于频繁的触发机制不太符合需求,所以我们需要用到change事件,它的特点就是值修改完成后才会触发。

对于select标签来说,change事件基本跟input是一样的,但是input有明显的特别之处,例如

只有值完成改变并且失去焦点的时候才会触发这个事件.

change事件当<input><select><textarea>的值发生变化时触发。它与input事件的最大不同,就是不会连续触发,只有当全部修改完成时才会触发,另一方面input事件必然伴随change事件。具体来说,分成以下几种情况。

  • 激活单选框(radio)或复选框(checkbox)时触发。
  • 用户提交时触发。比如,从下列列表(select)完成选择,在日期或文件输入框完成选择。
  • 当文本框或<textarea>元素的值发生改变,并且丧失焦点时触发。

如果比较一下上面input事件的例子,你会发现对于<select>元素来说,input和change事件基本是等价的。

invalid 事件

当表单提交时,如果表单的值不满足条件,那么就会触发invalid事件。

上面的代码中,由于表单是必填的,当用户未填写完成但是点击提交时,就会触发invalid事件

reset 事件

reset事件当表单重置(所有表单成员变回默认值)时触发。

submit 事件

submit事件当表单数据向服务器提交时触发。注意,submit事件的发生对象是<form>元素,而不是<button>元素,因为提交的是表单,而不是按钮。

inputEvent 事件对象

InputEvent接口主要用来描述input事件的实例。该接口继承了Event接口,还定义了一些自己的实例属性和实例方法。

浏览器原生提供InputEvent()构造函数,用来生成实例对象。

image.png

第一个参数是字符串,表示事件名称,该参数是必需的。第二个参数是一个配置对象,用来设置事件实例的属性,该参数是可选的。配置对象的字段除了Event构造函数的配置属性,还可以设置下面的字段,这些字段都是可选的。

e.data

这个接口返回的是变动的内容。

image.png

上面的代码会返回变动的文本内容,例如,在文本框中输入1,就会打印1,再输入2,就会打印2,如果此时删除,那么会返回null

e.inputType

这个接口用于输入的类型,包括以下内容:

  • 手动插入文本 insertText
  • 贴插入文本 insertFromPaste
  • 向后删除 deleteContentBackward
  • 向前删除 deleteContentForward

e.dataTransfer

InputEvent.dataTransfer属性返回一个 DataTransfer 实例。该属性只在文本框接受粘贴内容(insertFromPaste)或拖拽内容(insertFromDrop)时才有效。

回复

我来回复
  • 暂无回复内容