标准答案
- 规则可以按字段组织,例如 required、minLength、pattern、validator。
- validateField 负责校验单个字段,validate 负责校验整个表单。
- 校验结果应包含是否通过和错误信息,方便 UI 展示。
- 异步校验要返回 Promise,例如用户名是否重复。
- 实际项目还要考虑触发时机、脏状态、提交中状态、错误清理和跨字段校验。
题目解析
表单校验器的重点不是写几个 if,而是把校验规则变成可配置、可复用、可组合的结构。这样业务字段增加时,不需要把校验逻辑散落在事件回调里。
同步校验和异步校验最好统一成 Promise 流程。这样 required、正则校验和远程唯一性校验都可以走同一个 validate 方法。
跨字段校验是常见边界,比如确认密码依赖密码字段,开始时间不能晚于结束时间。规则函数需要拿到当前字段值,也要能拿到整个表单值。
代码示例
下面的实现支持字段规则数组、同步校验和异步校验。
JavaScript
async function validateField(values, field, rules) {
const value = values[field]
for (const rule of rules) {
if (rule.required && (value === undefined || value === null || value === '')) {
return rule.message || '必填项不能为空'
}
if (rule.pattern && !rule.pattern.test(String(value))) {
return rule.message || '格式不正确'
}
if (rule.validator) {
const result = await rule.validator(value, values)
if (result !== true) {
return typeof result === 'string' ? result : rule.message
}
}
}
return ''
}
async function validate(values, schema) {
const errors = {}
for (const field of Object.keys(schema)) {
const message = await validateField(values, field, schema[field])
if (message) {
errors[field] = message
}
}
return {
valid: Object.keys(errors).length === 0,
errors
}
}常见误区
- 校验逻辑散落在每个输入框事件里,无法复用和统一展示错误。
- 只支持同步校验,遇到远程唯一性检查就要重写结构。
- 跨字段规则拿不到完整表单值,确认密码、时间范围这类场景无法处理。