所有表单对象_【JavaScript 教程】浏览器—表单,FormData 对象

e9cbaa8b727bd901bd600c726c96f6e9.png

作者 | 阮一峰

1、表单概述

表单()用来收集用户提交的数据,发送到服务器。比如,用户提交用户名和密码,让服务器验证,就要通过表单。表单提供多种控件,让开发者使用,具体的控件种类和用法请参考 HTML 语言的教程。本章主要介绍 JavaScript 与表单的交互。

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

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

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

所有的键值对都会提交到服务器。但是,提交的数据格式跟元素的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 方法,所有键值对会连接成一行,作为 HTTP 请求的数据体发送到服务器,比如user_name=张三&user_passwd=123&submit_button=提交。下面就是 POST 请求的头信息。

POST /handling-page HTTP/1.1Host: example.comContent-Type: application/x-www-form-urlencodedContent-Length: 74user_name=张三&user_passwd=123&submit_button=提交

注意,实际提交的时候,只要键值不是 URL 的合法字符(比如汉字“张三”和“提交”),浏览器会自动对其进行编码。

点击submit控件,就可以提交表单。

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

上面表单就包含一个submit控件,点击这个控件,浏览器就会把表单数据向服务器提交。

注意,表单里面的元素如果没有用type属性指定类型,那么默认就是submit控件。

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

上面表单的元素,点击以后也会提交表单。

除了点击submit控件提交表单,还可以用表单元素的submit()方法,通过脚本提交表单。

formElement.submit();

表单元素的reset()方法可以重置所有控件的值(重置为默认值)。

formElement.reset()

2、FormData 对象

2.1、概述

表单数据以键值对的形式向服务器发送,这个过程是浏览器自动完成的。但是有时候,我们希望通过脚本完成过程,构造和编辑表单键值对,然后通过XMLHttpRequest.send()方法发送。浏览器原生提供了 FormData 对象来完成这项工作。

FormData 首先是一个构造函数,用来生成实例。

var formdata = new FormData(form);

FormData()构造函数的参数是一个表单元素,这个参数是可选的。如果省略参数,就表示一个空的表单,否则就会处理表单元素里面的键值对。

下面是一个表单。

<form id="myForm" name="myForm"><div><label for="username">用户名:label><input type="text" id="username" name="username">div><div><label for="useracc">账号:label><input type="text" id="useracc" name="useracc">div><div><label for="userfile">上传文件:label><input type="file" id="userfile" name="userfile">div><input type="submit" value="Submit!">form>

我们用 FormData 对象处理上面这个表单。

var myForm = document.getElementById('myForm');var formData = new FormData(myForm);// 获取某个控件的值
formData.get('username') // ""// 设置某个控件的值
formData.set('username', '张三');
formData.get('username') // "张三"

2.2、实例方法

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 实例,默认就会调用这个方法。

下面是get()getAll()set()append()方法的例子。

var formData = new FormData();
formData.set('username', '张三');
formData.append('username', '李四');
formData.get('username') // "张三"
formData.getAll('username') // ["张三", "李四"]
formData.append('userpic[]', myFileInput.files[0], 'user1.jpg');
formData.append('userpic[]', myFileInput.files[1], 'user2.jpg');

下面是遍历器的例子。

var formData = new FormData();
formData.append('key1', 'value1');
formData.append('key2', 'value2');for (var key of formData.keys()) {console.log(key);
}// "key1"// "key2"for (var value of formData.values()) {console.log(value);
}// "value1"// "value2"for (var pair of formData.entries()) {console.log(pair[0] + ': ' + pair[1]);
}// key1: value1// key2: value2// 等同于遍历 formData.entries()for (var pair of formData) {console.log(pair[0] + ': ' + pair[1]);
}// key1: value1// key2: value2

3、表单的内置验证

3.1、自动校验

表单提交的时候,浏览器允许开发者指定一些条件,它会自动验证各个表单控件的值是否符合条件。

<input required><input pattern="banana|cherry"><input minlength="6" maxlength="6"><input type="number" min="1" max="10"><input type="email"><input type="URL">

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

input:invalid {border-color: red;
}input,input:valid {border-color: #ccc;
}

3.2、checkValidity()

除了提交表单的时候,浏览器自动校验表单,还可以手动触发表单的校验。表单元素和表单控件都有checkValidity()方法,用于手动触发校验。

// 触发整个表单的校验
form.checkValidity()// 触发单个表单控件的校验
formControl.checkValidity()

checkValidity()方法返回一个布尔值,true表示通过校验,false表示没有通过校验。因此,提交表单可以封装为下面的函数。

function submitForm(action) {var form = document.getElementById('form');
form.action = action;if (form.checkValidity()) {
form.submit();
}
}

3.3、willValidate 属性

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

// HTML 代码如下// // // var input = document.querySelector('#name');
input.willValidate // true

3.4、validationMessage 属性

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

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

  • 该控件满足校验条件

// HTML 代码如下// document.querySelector('form input').validationMessage// "请填写此字段。"

下面是另一个例子。

var myInput = document.getElementById('myinput');if (!myInput.checkValidity()) {document.getElementById('prompt').innerHTML = myInput.validationMessage;
}

3.5、setCustomValidity()

控件元素的setCustomValidity()方法用来定制校验失败时的报错信息。它接受一个字符串作为参数,该字符串就是定制的报错信息。如果参数为空字符串,则上次设置的报错信息被清除。

这个方法可以替换浏览器内置的表单验证报错信息,参数就是要显示的报错信息。

<form action="somefile.php"><inputtype="text"name="username"placeholder="Username"pattern="[a-z]{1,15}"id="username"
><input type="submit">form>

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

var input = document.getElementById('username');
input.oninvalid = function (event) {
event.target.setCustomValidity('用户名必须是小写字母,不能为空,最长不超过15个字符'
);
}

上面代码中,setCustomValidity()方法是在invalid事件的监听函数里面调用。该方法也可以直接调用,这时如果参数不为空字符串,浏览器就会认为该控件没有通过校验,就会立刻显示该方法设置的报错信息。

/* HTML 代码如下
*/document.getElementById('fs').onchange = checkFileSize;function checkFileSize() {var fs = document.getElementById('fs');var files = fs.files;if (files.length > 0) {if (files[0].size > 75 * 1024) {
fs.setCustomValidity('文件不能大于 75KB');return;
}
}
fs.setCustomValidity('');
}

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

3.6、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:布尔值,表示用户没有填入必填的值。

下面是一个例子。

var input = document.getElementById('myinput');if (input.validity.valid) {console.log('通过校验');
} else {console.log('校验失败');
}

下面是另外一个例子。

var txt = '';if (document.getElementById('myInput').validity.rangeOverflow) {
txt = '数值超过上限';
}document.getElementById('prompt').innerHTML = txt;

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

var input = document.getElementById('username');var form = document.getElementById('form');var elem = document.createElement('div');
elem.id = 'notify';
elem.style.display = 'none';
form.appendChild(elem);
input.addEventListener('invalid', function (event) {
event.preventDefault();if (!event.target.validity.valid) {
elem.textContent = '用户名必须是小写字母';
elem.className = 'error';
elem.style.display = 'block';
input.className = 'invalid animated shake';
}
});
input.addEventListener('input', function(event){if ( 'block' === elem.style.display ) {
input.className = '';
elem.style.display = 'none';
}
});

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

3.7、表单的 novalidate 属性

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

<form novalidate>form>

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

form.noValidate = true;

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

<form><input type="submit" value="submit" formnovalidate>form>

4、enctype 属性

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

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

The first line.
The second line.

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

(1)GET 方法

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

<formaction="register.php"method="get"onsubmit="AJAXSubmit(this); return false;"
>form>

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

?foo=bar&baz=The%20first%20line.%0AThe%20second%20line.

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

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

<formaction="register.php"method="post"onsubmit="AJAXSubmit(this); return false;"
>form>

发送的 HTTP 请求如下。

Content-Type: application/x-www-form-urlencodedfoo=bar&baz=The+first+line.%0D%0AThe+second+line.%0D%0A

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

(3)text/plain

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

<formaction="register.php"method="post"enctype="text/plain"onsubmit="AJAXSubmit(this); return false;"
>form>

发送的 HTTP 请求如下。

Content-Type: text/plainfoo=bar
baz=The first line.
The second line.

(4)multipart/form-data

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

<formaction="register.php"method="post"enctype="multipart/form-data"onsubmit="AJAXSubmit(this); return false;"
>form>

发送的 HTTP 请求如下。

Content-Type: multipart/form-data; boundary=---------------------------314911788813839-----------------------------314911788813839
Content-Disposition: form-data; name="foo"
bar-----------------------------314911788813839
Content-Disposition: form-data; name="baz"
The first line.
The second line.-----------------------------314911788813839--

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

5、文件上传

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

<input type="file" id="file" name="myFile">

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

<form method="post" enctype="multipart/form-data"><div><label for="file">选择一个文件label><input type="file" id="file" name="myFile" multiple>div><div><input type="submit" id="submit" name="submit_button" value="上传" />div>form>

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

var fileSelect = document.getElementById('file');var files = fileSelect.files;

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

var formData = new FormData();for (var i = 0; i < files.length; i++) {var file = files[i];// 只上传图片文件if (!file.type.match('image.*')) {continue;
}
formData.append('photos[]', file, file.name);
}

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

var xhr = new XMLHttpRequest();
xhr.open('POST', 'handler.php', true);
xhr.onload = function () {if (xhr.status !== 200) {console.log('An error occurred!');
}
};
xhr.send(formData);

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

var file = document.getElementById('test-input').files[0];var xhr = new XMLHttpRequest();
xhr.open('POST', 'myserver/uploads');
xhr.setRequestHeader('Content-Type', file.type);
xhr.send(file);

本文完~

推荐阅读

【JavaScript 教程】浏览器模型—Cookie

Navigator 对象,Screen 对象。

【JavaScript 教程】浏览器—window 对象

【JavaScript 教程】浏览器—浏览器环境概述

XMLHttpRequest 对象

【JavaScript 教程】浏览器—同源限制

【JavaScript 教程】浏览器—CORS 通信

【JavaScript 教程】浏览器—Storage 接口

【JavaScript 教程】浏览器—History 对象

Location 对象,URL 对象,URLSearchParams 对象

【JavaScript 教程】浏览器—ArrayBuffer 对象,Blob 对象

1e4be1801da80cc4fcf8e7dca53ec77d.png

45bd4eb60c9eacd1d1753c0f6400d89b.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值