约束验证
创建 Web 表单一直是一项复杂的任务。虽然标记表单本身很容易,但检查每个字段是否具有有效且一致的值更难,告知用户问题可能会让人头疼。 HTML5 为表单引入了新的机制:它为 <input>
元素添加了新的语义类型以及约束验证,以简化在客户端检查表单内容的工作。基本且常见的约束可以在没有 JavaScript 的情况下进行检查,方法是设置新属性;更复杂的约束可以使用约束验证 API 进行测试。
有关这些概念的基本介绍,以及示例,请参阅 表单验证教程。
注意:HTML 约束验证不会消除对服务器端验证的需求。即使预期收到无效表单请求的数量要少得多,但仍然可以通过多种方式发送无效请求
- 通过浏览器开发者工具修改 HTML。
- 通过手工制作 HTTP 请求,而不用表单。
- 通过编程方式将内容写入表单(某些约束验证*仅对*用户输入执行,而不会在使用 JavaScript 设置表单字段的值时执行)。
因此,您应该始终在服务器端验证表单数据,与客户端的操作保持一致。
内在约束和基本约束
语义输入类型
用于type
属性的内在约束是
输入类型 | 约束描述 | 关联违规 |
---|---|---|
<input type="URL"> |
该值必须是一个绝对URL,如URL 实施标准中所定义。 | TypeMismatch 约束违规 |
<input type="email"> |
该值必须是语法上有效的电子邮件地址,通常格式为[email protected] ,但也可以是本地的,例如username@hostname 。 |
TypeMismatch 约束违规 |
对于这两种输入类型,如果multiple
属性已设置,则可以设置多个值,以逗号分隔的列表形式。如果这些值中任何一个不满足此处描述的条件,则会触发Type mismatch 约束违规。
请注意,大多数输入类型没有内在约束,因为某些类型被禁止进行约束验证,或者具有一个将不正确值转换为正确默认值的清理算法。
与验证相关的属性
除了上面描述的type
属性外,以下属性用于描述基本约束
属性 | 支持该属性的输入类型 | 可能的值 | 约束描述 | 关联违规 |
---|---|---|---|---|
pattern |
text , search , url , tel , email , password |
一个JavaScript 正则表达式(使用global 、ignoreCase 和multiline 标志*禁用*编译) |
该值必须与模式匹配。 |
patternMismatch 约束违规 |
min |
range , number |
一个有效的数字 | 该值必须大于或等于该值。 |
rangeUnderflow 约束违规 |
date , month , week |
一个有效的日期 | |||
datetime-local , time |
一个有效的日期和时间 | |||
max |
range , number |
一个有效的数字 | 该值必须小于或等于该值 |
rangeOverflow 约束违规 |
date , month , week |
一个有效的日期 | |||
datetime-local , time |
一个有效的日期和时间 | |||
required |
text , search , url , tel , email , password , date , datetime-local , month , week , time , number , checkbox , radio , file ;也适用于<select> 和<textarea> 元素 |
none 因为它是一个布尔属性:存在表示true,不存在表示false | 必须有一个值(如果已设置)。 |
valueMissing 约束违规 |
step |
date |
一个整天的天数 | 除非 step 设置为any 文本,否则该值必须是min 加上 step 的整数倍。 |
stepMismatch 约束违规 |
month |
一个整数的月数 | |||
week |
一个整数的周数 | |||
datetime-local , time |
一个整数的秒数 | |||
range , number |
一个整数 | |||
minlength |
text , search , url , tel , email , password ;也适用于<textarea> 元素 |
一个整数长度 | 字符(代码点)的数量不得小于属性的值(如果非空)。对于<textarea> ,所有换行符都被规范化为单个字符(而不是 CRLF 对)。 |
tooShort 约束违规 |
maxlength |
text , search , url , tel , email , password ;也适用于<textarea> 元素 |
一个整数长度 | 字符(代码点)的数量不得超过属性的值。 |
tooLong 约束违规 |
约束验证过程
约束验证是通过约束验证 API 在单个表单元素上或在表单级别上,在<form>
元素本身完成的。约束验证以以下方式完成
- 通过调用表单关联的 DOM 接口的
checkValidity()
或reportValidity()
方法(HTMLInputElement
、HTMLSelectElement
、HTMLButtonElement
、HTMLOutputElement
或HTMLTextAreaElement
),这仅评估该元素上的约束,允许脚本获取此信息。checkValidity()
方法返回一个布尔值,指示元素的值是否通过其约束。(这通常由用户代理在确定使用哪种 CSS 伪类:valid
或:invalid
时完成。)相反,reportValidity()
方法将任何约束失败报告给用户。 - 通过调用
HTMLFormElement
接口上的checkValidity()
或reportValidity()
方法。 - 通过提交表单本身。
调用checkValidity()
被称为*静态地*验证约束,而调用reportValidity()
或提交表单被称为*交互式地*验证约束。
注意
- 如果
novalidate
属性已设置在<form>
元素上,则不会进行约束的交互式验证。 - 在
HTMLFormElement
接口上调用submit()
方法不会触发约束验证。换句话说,即使该方法不满足约束,也会将表单数据发送到服务器。改为在提交按钮上调用click()
方法。 minlength
和maxlength
约束仅对用户提供的输入进行检查。即使显式调用checkValidity()
或reportValidity()
,也不会在以编程方式设置值时检查它们。
使用约束验证 API 的复杂约束
使用 JavaScript 和约束 API,可以实现更复杂的约束,例如,组合多个字段的约束,或涉及复杂计算的约束。
基本上,其理念是在某些表单字段事件(如onchange)上触发 JavaScript 以计算约束是否被违反,然后使用field.setCustomValidity()
方法设置验证结果:空字符串表示约束满足,任何其他字符串都表示出现错误,该字符串是显示给用户的错误消息。
组合多个字段的约束:邮政编码验证
邮政编码格式因国家/地区而异。大多数国家/地区不仅允许使用国家/地区代码的可选前缀(例如德国的D-
,法国或瑞士的F-
),而且有些国家/地区的邮政编码只有固定位数;其他国家/地区,如英国,具有更复杂的结构,允许在某些特定位置使用字母。
注意:这不是一个完整的邮政编码验证库,而只是一个对关键概念的演示。
例如,我们将添加一个脚本,用于检查此简单表单的约束验证
<form>
<label for="ZIP">ZIP : </label>
<input type="text" id="ZIP" />
<label for="Country">Country : </label>
<select id="Country">
<option value="ch">Switzerland</option>
<option value="fr">France</option>
<option value="de">Germany</option>
<option value="nl">The Netherlands</option>
</select>
<input type="submit" value="Validate" />
</form>
这将显示以下表单
首先,我们编写一个函数来检查约束本身
function checkZIP() {
// For each country, defines the pattern that the ZIP has to follow
const constraints = {
ch: [
"^(CH-)?\\d{4}$",
"Switzerland ZIPs must have exactly 4 digits: e.g. CH-1950 or 1950",
],
fr: [
"^(F-)?\\d{5}$",
"France ZIPs must have exactly 5 digits: e.g. F-75012 or 75012",
],
de: [
"^(D-)?\\d{5}$",
"Germany ZIPs must have exactly 5 digits: e.g. D-12345 or 12345",
],
nl: [
"^(NL-)?\\d{4}\\s*([A-RT-Z][A-Z]|S[BCE-RT-Z])$",
"Netherland ZIPs must have exactly 4 digits, followed by 2 letters except SA, SD and SS",
],
};
// Read the country id
const country = document.getElementById("Country").value;
// Get the NPA field
const ZIPField = document.getElementById("ZIP");
// Build the constraint checker
const constraint = new RegExp(constraints[country][0], "");
console.log(constraint);
// Check it!
if (constraint.test(ZIPField.value)) {
// The ZIP follows the constraint, we use the ConstraintAPI to tell it
ZIPField.setCustomValidity("");
} else {
// The ZIP doesn't follow the constraint, we use the ConstraintAPI to
// give a message about the format required for this country
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">Select a file smaller than 75 kB : </label>
<input type="file" id="FS" />
这将显示
JavaScript 读取选定的文件,使用File.size()
方法获取其大小,将其与(硬编码的)限制进行比较,并调用约束 API 以告知浏览器是否存在违规
function checkFileSize() {
const FS = document.getElementById("FS");
const files = FS.files;
// If there is (at least) one file selected
if (files.length > 0) {
if (files[0].size > 75 * 1024) {
// Check the constraint
FS.setCustomValidity("The selected file must not be larger than 75 kB");
FS.reportValidity();
return;
}
}
// No custom constraint violation
FS.setCustomValidity("");
}
最后,我们将该方法与正确的事件挂钩
window.onload = () => {
document.getElementById("FS").onchange = checkFileSize;
};
约束验证的视觉样式
除了设置约束之外,Web 开发人员还希望控制向用户显示的消息以及消息的样式。
控制元素的外观
控制约束违规的文本
以下项目可以帮助控制约束违规的文本
- 以下元素上的
setCustomValidity(message)
方法<fieldset>
。注意:在 fieldset 元素上设置自定义有效性消息不会阻止大多数浏览器中的表单提交。<input>
<output>
<select>
- 提交按钮(使用具有
submit
类型的<button>
元素或具有submit 类型的input
元素创建。其他类型的按钮不参与约束验证)。 <textarea>
ValidityState
接口描述了上面列出的元素类型的validity
属性返回的对象。它表示输入值无效的各种方式。它们共同帮助解释了为什么元素的值无效(如果它无效)。