uni-app 表单验证需确保 rules 字段名与 model 顶层 key 严格一致、正则书写正确(如手机号/^1[3-9]d{9}$/)、confirm password 必须用 validator 动态比对、v-model 值类型与 pattern 匹配,并且每字段 rules 数组不可省略。

uni-app 表单验证不用手写校验函数也能跑通,但直接套 rules + uni-forms 容易卡在字段名不匹配、正则写错、v-model 绑定失效这三处。
uni-forms 的 rules 字段名必须和 model 对象 key 严格一致
很多人把 rules 写成 { phone: { ... } },但 model 却是 { userInfo: { phone: '' } },结果校验永远不触发。这是因为 uni-forms 不支持嵌套路径自动解析 —— 它只认顶层 key。
- ✅ 正确写法:model 是扁平对象
{ phone: '', email: '' },rules 就写{ phone: { rules: [...] }, email: { rules: [...] } } - ⚠️ 如果必须用嵌套结构(比如
userInfo.phone),得手动用validateField('userInfo.phone')触发,且uni-forms-item的name属性也得设为"userInfo.phone"(字符串,不是表达式) - ❌ 不要写
name="userInfo.phone"却在 rules 里配userInfo: { phone: { ... } },规则不会命中
手机号 / 邮箱正则别直接抄网上老版本
很多博客贴的手机号正则还用 /^1[3|4|5|6|7|8|9][0-9]{9}$/,竖线 | 在字符组里没意义,实际会匹配 13、14、1| 这种非法组合。邮箱正则漏掉国际化域名或大小写处理,也会在 iOS 或微信小程序里校验失败。
- ✅ 推荐手机号:
/^1[3-9]d{9}$/(简洁、覆盖全部号段、无歧义) - ✅ 推荐邮箱:
/^w+([.-]?w+)*@w+([.-]?w+)*.w+([.-]?w+)*$/(兼容带连字符/点的域名,不强制小写) - ⚠️
pattern里写正则字面量时,斜杠/不要加 ——pattern接收字符串,写成pattern="/^1[3-9]\d{9}$/"会报错;正确是pattern: "^1[3-9]\d{9}$"
confirm password 校验不能只靠 pattern
确认密码需要动态比对新密码字段值,pattern 是静态正则,做不到。必须用 validator 函数,且注意异步回调时机。
- ✅ 正确写法(setup script):
const rules = { newPassword: { rules: [{ required: true, errorMessage: '新密码不能为空' }] }, confirmPassword: { rules: [{ validator: (rule, value) => { return value === formData.newPassword || '两次输入的密码不一致' } }] } } - ⚠️ 不要用
required: true+pattern模拟,value 为空时validator仍会执行,需自行判空 - ⚠️ 若
formData是ref,validator 里读formData.newPassword.value,否则拿不到最新值
validate() 报错但没提示?检查 uni-easyinput 的 type 和 v-model 绑定
常见现象:点提交,validate() 返回 promise reject,但控制台没错误,页面也没提示。大概率是 uni-easyinput 的 type="number" 导致 v-model 绑定值变成 number 类型,而 rules 里的 pattern 校验的是字符串 —— /^1[3-9]d{9}$/.test(13812345678) 必然 false。
- ✅ 解决:统一用
type="text",或在validator里先String(value)转类型 - ✅ 确保
v-model绑定的是响应式变量(ref或reactive的属性),不要绑定字面量或常量 - ⚠️
uni-easyinput的maxlength是字符串长度限制,和正则位数无关;11 位手机号设maxlength="11"是对的,但正则仍要写d{9}(因为开头1已固定)
最常被忽略的是:rules 里每个字段的 rules 数组必须存在,哪怕只有一条规则,也不能写成 phone: { required: true } —— 缺少 rules: [] 包裹,整个字段校验直接静默跳过。


















