HTML 表单验证
表单验证确保用户提交的数据符合预期格式。HTML 提供了浏览器内置验证,无需 JavaScript。对于复杂场景,也可以使用 Constraint Validation API。
本章后半部分涉及 JavaScript 代码(Constraint Validation API、自定义验证逻辑)。如果你尚未学习 JavaScript,可以仅阅读”浏览器内置验证”和”CSS 伪类”两节,后续需深入时再回来查阅。
浏览器内置验证
通过属性组合即可实现基础验证:
html
<form>
<input type="text" name="username" required minlength="3" maxlength="20">
<input type="email" name="email" required>
<input type="number" name="age" min="1" max="150">
<input type="password" name="password" required pattern=".{8,}">
<button type="submit">提交</button>
</form> 浏览器会阻止提交并在无效字段旁显示提示(提示文字因浏览器而异)。
自定义验证信息
使用 Constraint Validation API 可以定制错误消息和验证逻辑:
javascript
const emailInput = document.querySelector('input[name="email"]');
emailInput.addEventListener('input', () => {
if (emailInput.validity.typeMismatch) {
emailInput.setCustomValidity('请输入有效的邮箱地址');
} else if (emailInput.validity.valueMissing) {
emailInput.setCustomValidity('邮箱不能为空');
} else {
emailInput.setCustomValidity(''); // 清除自定义错误
}
}); ValidityState 属性
每个表单控件都有一个 validity 对象,包含以下布尔属性:
| 属性 | 含义 |
|---|---|
valueMissing | 必填字段为空 |
typeMismatch | 值与 type 不匹配(如 email 不含 @) |
patternMismatch | 值与 pattern 正则不匹配 |
tooLong / tooShort | 文本过长/过短 |
rangeUnderflow / rangeOverflow | 数字超出 min/max |
stepMismatch | 数字不符合 step |
badInput | 浏览器无法解析输入 |
valid | 所有约束都满足 |
javascript
const form = document.querySelector('form');
form.addEventListener('submit', (e) => {
if (!form.checkValidity()) {
e.preventDefault();
// 遍历所有控件,显示自定义错误
form.querySelectorAll(':invalid').forEach(el => {
console.log(el.name, el.validationMessage);
});
}
}); 实时验证(表单提交前)
javascript
const inputs = document.querySelectorAll('input');
inputs.forEach(input => {
input.addEventListener('blur', () => {
// 失去焦点时验证
validateField(input);
});
input.addEventListener('input', () => {
// 如果之前有错误,实时清除
if (input.validity.valid) {
clearError(input);
}
});
});
function validateField(field) {
const errorSpan = document.getElementById(`${field.name}-error`);
if (!field.validity.valid) {
field.classList.add('invalid');
errorSpan.textContent = field.validationMessage;
} else {
field.classList.remove('invalid');
errorSpan.textContent = '';
}
} reportValidity() 与 checkValidity()
javascript
// checkValidity() — 仅返回 true/false,不触发 UI 提示
if (input.checkValidity()) { /* 有效 */ }
// reportValidity() — 返回 true/false,并触发浏览器的 UI 提示
if (!input.reportValidity()) { /* 无效,已显示错误 */ } CSS 伪类
浏览器为验证状态提供了 CSS 伪类,可直接控制样式:
css
input:valid { border-color: green; }
input:invalid { border-color: red; }
input:required { border-left-color: var(--color-accent); }
input:optional { border-style: dashed; }
input:in-range { background: #f0fff0; }
input:out-of-range { background: #fff0f0; } :invalid 伪类在页面加载时就生效,意味着用户还没开始填写,必填的空字段就已经被标记为无效。最好在用户交互后才触发——结合 JavaScript 或使用 :user-invalid(更新的伪类,在用户尝试提交后才触发)。
完整的验证示例
html
<form id="signup" novalidate>
<div>
<label for="name">姓名</label>
<input type="text" id="name" name="name" required minlength="2">
<span class="error" id="name-error"></span>
</div>
<div>
<label for="email">邮箱</label>
<input type="email" id="email" name="email" required>
<span class="error" id="email-error"></span>
</div>
<div>
<label for="password">密码</label>
<input type="password" id="password" name="password"
required minlength="8"
pattern="^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$">
<span class="error" id="password-error"></span>
<small>至少 8 位,包含字母和数字</small>
</div>
<button type="submit">注册</button>
</form> novalidate 禁用浏览器原生提示,由 JavaScript 接管所有验证提示,保持跨浏览器一致的 UI。