约束验证:技术文档整理
创建 web 表单始终是一个复杂的任务。仅仅组装表单是容易的,但是检查每一个字段的值是否有效并且一致是一件更加困难的事情,而如何告知用户错误所在可能会令人头痛。HTML5 引入了表单相关的一些新机制:它为 input 元素和约束验证增加了一些新的语义类型,使得客户端检查表单内容变得容易。基本上,通过
创建 web 表单始终是一个复杂的任务。仅仅组装表单是容易的,但是检查每一个字段的值是否有效并且一致是一件更加困难的事情,而如何告知用户错误所在可能会令人头痛。HTML5 引入了表单相关的一些新机制:它为 input 元素和约束验证增加了一些新的语义类型,使得客户端检查表单内容变得容易。基本上,通过设置一些新的属性,常用的约束条件可以无需 JavaScript 代码而检测到;对于更复杂的约束条件的校验可以尝试使用约束验证 API。
对于这些概念的基本介绍和示例,参阅表单数据校验教程一页的介绍。
注意: HTML 约束验证并不能移除服务端验证的需要。尽管无效的表单请求要少得多,但无效的表单请求仍然可能被发送,例如被试图欺骗你的网络应用的坏人发送。因此,你需要始终在服务端验证输入约束,其方式与在客户端所做的一致。
固有和基本的约束
在 HTML 中,有两种方式声明基本的约束:
- 给
input元素的type属性选择最合适的语义化的值,比如,选择email类型将会自动创建一个约束,用于检查输入的值是否是一个有效的电子邮件地址。 - 设置验证相关的属性值,允许用一种简单的方式来描述基本的约束,而不必要使用 JavaScript。
语义的 input 类型
type 属性中的固有约束有:
| Input 类型 | 约束描述 | 相关违约 |
|---|---|---|
<input type="URL"> |
值必须为 URL 现行标准定义的绝对 URL 地址。 | TypeMismatch 约束违反 |
<input type="email"> |
该值必须是一个语法上有效的电子邮件地址,其格式一般为 username@hostname.tld,但也可以是本地的,如 username@hostname。 |
TypeMismatch 约束违反 |
对于这两种输入类型,如果设置了 multiple 属性,可以设置几个值,作为一个逗号分隔的列表。如果其中任何一个不满足这里描述的条件,就会触发 TypeMismatch 约束的违反。
请注意,大多数 input 类型没有内在的约束,因为有些类型被禁止在约束验证中使用,或者有一个净化算法将不正确的值转化为正确的默认值。
验证相关的属性
除了上面描述的 type 属性外,以下属性用于描述基本约束。
属性
支持该特性的 Input 类型
可接受的值
约束描述
相关违约
<code
>pattern</code
>
text、search、url、tel、email、password
一个<a href="/zh-CN/docs/Web/JavaScript/Guide/Regular_expressions"
>JavaScript 正则表达式</a
>(以 `RegExp.global`、`RegExp.ignoreCase` 标志编译,且禁用了 `RegExp.multiline` 标志)
输入的值必须符合模式。
<a href="/zh-CN/docs/Web/API/ValidityState/patternMismatch"
>patternMismatch</a
>
约束违反
min
range、number
一个有效的数字
输入的值必须大于等于该属性值。
<strong
><code
><a href="/zh-CN/docs/Web/API/ValidityState/rangeUnderflow"
>rangeUnderflow</a
></code
></strong
>
约束违反
date、month、week
一个有效的日期值
datetime-local、time
一个有效的日期时间值
max
range、number
一个有效的数字
输入的值必须小于等于该属性值。
<strong
><code
><a href="/zh-CN/docs/Web/API/ValidityState/rangeOverflow"
>rangeOverflow</a
></code
></strong
>
约束违反
date、month、week
一个有效的日期值
datetime-local、time
一个有效的日期时间值
<code
>required</code
>
text、search、url、tel、email、password、date、datetime-local、month、week、time、number、checkbox、radio、file;也在 `select` 和 `textarea` 元素上可用
由于是一个布尔属性,所以为 none:如果存在这个属性,则为 true;否则为 false
如果指定了这个属性,则必须输入一个值。
<strong
><code
><a href="/zh-CN/docs/Web/API/ValidityState/valueMissing"
>valueMissing</a
></code
></strong
>
约束违反
step
date
一个代表天数的整数
如果 step 没有设置为字面量 any,则输入值必须为 min + step 值的整数倍。
<strong
><code
><a href="/zh-CN/docs/Web/API/ValidityState/stepMismatch"
>stepMismatch</a
></code
></strong
>
约束违反
month
一个代表月数的整数
week
一个代表周数的整数
datetime-local、time
一个代表秒数的整数
range、number
一个整数
<code
><a href="/zh-CN/docs/Web/HTML/Reference/Attributes/minlength"
>minlength</a
></code
>
text、search、url、tel、email、password;也在 `textarea` 元素上可用
一个整数长度
如果输入值非空,则其字符数(码点)不得少于该属性的值。对于 `textarea`,所有换行符都被规范化为一个字符(相对于 CRLF 对)。
<strong
><code
><a href="/zh-CN/docs/Web/API/ValidityState/tooShort"
>tooShort</a
></code
></strong
>
约束违反
<code
><a href="/zh-CN/docs/Web/HTML/Reference/Attributes/maxlength"
>maxlength</a
></code
>
text、search、url、tel、email、password;也在 `textarea` 元素上可用
一个整数长度
字符数(码点)不得超过该属性的值。
<strong
><code
><a href="/zh-CN/docs/Web/API/ValidityState/tooLong"
>tooLong</a
></code
></strong
>
约束违反
约束验证过程
约束验证是通过约束验证 API 在单个表单元素上或在表单层面上,通过 form 元素本身完成。约束验证是通过以下方式完成的:
- 通过调用表单相关的 DOM 接口(
HTMLInputElement、HTMLSelectElement、HTMLButtonElement、HTMLOutputElement或HTMLTextAreaElement)的checkValidity()或reportValidity()方法,只对这个元素进行约束评估,允许脚本获得这些信息。checkValidity()方法返回一个布尔值,表示该元素的值是否通过其约束(这通常是由用户代理在确定哪个 CSS 伪类,:valid或:invalid适用时完成的)。相反,reportValidity()方法会向用户报告任何约束失败的情况。 - 通过调用
HTMLFormElement接口上的checkValidity()或reportValidity()方法。 - 通过提交表单本身。
调用 checkValidity() 也被称为约束的静态验证,调用 reportValidity() 也被称为约束的交互认证。
注意:
- 如果
form元素上设置了novalidate属性,则不发生约束验证交互。- 在
HTMLFormElement接口上调用submit()方法并不触发约束条件验证。换句话说,即使表单数据不满足约束条件,该方法也会将其发送到服务器。在提交按钮上调用click()方法来代替。
使用约束验证 API 进行复杂的约束
使用 JavaScript 和约束验证 API,可以实现更复杂的约束,例如,结合几个字段的约束,或涉及复杂计算的约束。
基本上,这个想法是在某个表单字段事件(比如 onchange)上触发 JavaScript,以计算是否违反约束,然后使用 field.setCustomValidity() 方法来设置验证的结果:一个空字符串意味着满足约束条件,任何其他字符串意味着有一个错误,这个字符串是显示给用户的错误信息。
包含多个字段的约束:邮政编码验证
每个国家的邮政编码都不相同。大多数国家允许有一个可选的国家代码前缀(如德国的 D-,法国或瑞士的 F-),还有其他一些国家的邮政编码只有固定的数字;其他国家,如英国,有更复杂的结构,允许在一些特定的位置有字母。
注意: 这不是一个全面的邮政编码验证库,而是关键概念的演示。
作为示例,我们会向以下这个简单的表单中添加一段代码来进行约束验证:
<form>
<label for="ZIP">ZIP 码:</label>
<input type="text" id="ZIP" />
<label for="Country">国家:</label>
<select id="Country">
<option value="ch">瑞士</option>
<option value="fr">法国</option>
<option value="de">德国</option>
<option value="nl">荷兰</option>
</select>
<input type="submit" value="验证" />
</form>
以上代码显示了像这样的表单:
交互示例与兼容性表格请参阅原文。
首先,我们来写一个函数来检查本身包含的约束:
function checkZIP() {
// 为每个国家定义 ZIP 码需要满足的模式
const constraints = {
ch: [
"^(CH-)?\\d{4}$",
"瑞士的 ZIP 码必须恰好有 4 位数字,如 CH-1950 或 1950",
],
fr: [
"^(F-)?\\d{5}$",
"法国的 ZIP 码必须恰好有 5 位数字,如 F-75012 或 75012",
],
de: [
"^(D-)?\\d{5}$",
"德国的 ZIP 码必须恰好有 5 位数字,如 D-12345 或 12345",
],
nl: [
"^(NL-)?\\d{4}\\s*([A-RT-Z][A-Z]|S[BCE-RT-Z])$",
"荷兰的 ZIP 码必须恰好有 4 位数字,后跟除 SA、SD 和 SS 的 2 位字母",
],
};
// 读取国家 ID
const country = document.getElementById("Country").value;
// 获取 NPA 字段内容
const ZIPField = document.getElementById("ZIP");
// 构建约束检查器
const constraint = new RegExp(constraints[country][0], "");
console.log(constraint);
// 检查它!
if (constraint.test(ZIPField.value)) {
// ZIP 码满足约束条件,我们使用 Constraint API 告知用户
ZIPField.setCustomValidity("");
} else {
// ZIP 不满足约束条件,我们使用 Constraint API 告知该国家所需的 ZIP 码格式
ZIPField.setCustomValidity(constraints[country][1]);
}
}
然后我们把它链接到 select 的 onchange 事件和 input 的 oninput 事件。
window.onload = () => {
document.getElementById("Country").onchange = checkZIP;
document.getElementById("ZIP").oninput = checkZIP;
};
限制所上传文件的大小
另一个常见的约束是限制要上传的文件的大小。在文件传输到服务器之前,在客户端检查这个问题需要将约束条件验证 API,特别是 field.setCustomValidity() 方法,与另一个 JavaScript API 结合起来,这里是文件 API。
这里是 HTML 部分:
<label for="FS">选择一个小于 75 kB 的文件:</label>
<input type="file" id="FS" />
会显示:
交互示例与兼容性表格请参阅原文。
JavaScript 代码会读取所选的文件,使用 File.size() 方法来获取其大小,将其与(硬编码的)限制进行比较,如果有违反,则调用约束 API 来通知浏览器。
function checkFileSize() {
const FS = document.getElementById("FS");
const files = FS.files;
// 如果选择了(至少)一个文件
if (files.length > 0) {
if (files[0].size > 75 * 1024) {
// 检查约束条件
FS.setCustomValidity("选择的文件不能超过 75 kB");
return;
}
}
// 没有违反自定义约束条件
FS.setCustomValidity("");
}
最终,我们将这个方法链接到一个正确的事件上:
window.onload = () => {
document.getElementById("FS").onchange = checkFileSize;
};
约束验证的可视化样式
除了设置约束条件外,web 开发者还想控制向用户显示什么信息以及它们的样式。
控制元素的外观
元素的外观可以通过 CSS 伪类进行控制。
:required、:optional CSS 伪类
:required 和 :optional 伪类允许开发者编写选择器,以匹配有 required 属性或没有该属性的表单元素。
:placeholder-shown CSS 伪类
参见 :placeholder-shown。
:valid、:invalid CSS 伪类
:valid 和 :invalid 伪类用于表示 \ 元素,根据输入的类型设置,这些元素的内容分别可以验证和无法验证。这些类允许用户对有效或无效的表单元素进行样式设计,以使其更容易识别格式正确或不正确的元素。
控制约束验证的文字
以下一些方法可以控制违反约束条件的文本:
-
以下元素上的
setCustomValidity(message)方法:fieldset。备注:大多数浏览器中,在 fieldset 元素上设定自定义验证信息不会阻止表单提交。inputoutputselect- 提交按钮(使用类型为
submit的button元素,或类型为input/submit的input元素创建。其他类型的按钮不参与约束验证。 textarea
-
ValidityState接口描述了由上述元素类型的validity属性返回的对象。它表示一个输入值可能无效的各种方式。它们共同解释了为什么一个元素的值是无效的,则不能被验证。
来源与授权
本文依据 约束验证 整理,原作者为 Mozilla Contributors,按 CC BY-SA 2.5 授权发布。转换为本站排版;移除导航宏与内嵌交互程序;图片改为原图链接。正文整理按CC BY-SA 2.5发布。
本站日期是整理发布的日期,不代表原文首次发布或最近更新的时间。代码示例授权及其适用范围请核对原文的授权说明。