如果你写过表单,一定有过这种体验:
-
校验逻辑散落在各个按钮里
-
一个字段改规则,要改 5 个地方
-
UI 和校验代码混在一起
-
状态一多,表单直接失控
这篇文章的目标只有一个:
教你用 HarmonyOS 的正确方式,写一个"可维护、可扩展、不崩盘"的复杂表单体系
一、真实项目中的"复杂表单"长什么样?
我们以一个用户资料编辑页为例,字段包括:
-
用户名(必填,长度限制)
-
手机号(格式校验)
-
邮箱(格式校验)
-
年龄(范围校验)
-
是否接收通知(开关)
-
提交前整体校验
-
错误提示实时反馈
📌 这已经是一个中等复杂度的真实表单。
二、先说结论:表单该怎么设计?
一句话总结:
表单 = 状态模型 + 校验规则 + UI 映射
而不是:
❌ 一堆 TextInput + onClick 判断
三、第一步:定义表单数据模型(核心)
model/ProfileFormModel.ets
@ObservedV2
export class ProfileForm {
name: string = ''
phone: string = ''
email: string = ''
age: number = 0
notify: boolean = false
errors: Record<string, string> = {}
}
📌 表单数据
📌 错误信息
📌 都集中在一个模型里
四、第二步:封装校验规则(非常关键)
不要把校验写在 UI 里。
service/FormValidator.ets
export class FormValidator {
static validateName(name: string): string {
if (!name) return '用户名不能为空'
if (name.length < 2) return '用户名至少 2 个字符'
return ''
}
static validatePhone(phone: string): string {
const reg = /^1\d{10}$/
if (!reg.test(phone)) return '手机号格式不正确'
return ''
}
static validateEmail(email: string): string {
if (!email.includes('@')) return '邮箱格式不正确'
return ''
}
static validateAge(age: number): string {
if (age <= 0 || age > 120) return '年龄不合法'
return ''
}
}
📌 校验逻辑完全与 UI 解耦
📌 后续规则变更只改这一处
五、第三步:在 Store 中统一调度校验
store/ProfileFormStore.ets
import { ProfileForm } from '../model/ProfileFormModel'
import { FormValidator } from '../service/FormValidator'
@ObservedV2
export class ProfileFormStore {
form = new ProfileForm()
validateField(field: string) {
let msg = ''
switch (field) {
case 'name':
msg = FormValidator.validateName(this.form.name)
break
case 'phone':
msg = FormValidator.validatePhone(this.form.phone)
break
case 'email':
msg = FormValidator.validateEmail(this.form.email)
break
case 'age':
msg = FormValidator.validateAge(this.form.age)
break
}
this.form.errors[field] = msg
}
validateAll(): boolean {
this.validateField('name')
this.validateField('phone')
this.validateField('email')
this.validateField('age')
return Object.values(this.form.errors).every(v => !v)
}
}
📌 UI 不做判断
📌 UI 只展示结果
📌 校验入口统一
六、第四步:表单页面实现(UI 只负责"映射")
pages/ProfileEdit.ets
@ComponentV2
struct ProfileEdit {
@Local store = new ProfileFormStore()
build() {
Column({ space: 12 }) {
TextInput({ placeholder: '用户名' })
.onChange(v => {
this.store.form.name = v
this.store.validateField('name')
})
this.errorText('name')
TextInput({ placeholder: '手机号' })
.onChange(v => {
this.store.form.phone = v
this.store.validateField('phone')
})
this.errorText('phone')
TextInput({ placeholder: '邮箱' })
.onChange(v => {
this.store.form.email = v
this.store.validateField('email')
})
this.errorText('email')
TextInput({ placeholder: '年龄', type: InputType.Number })
.onChange(v => {
this.store.form.age = Number(v)
this.store.validateField('age')
})
this.errorText('age')
Toggle({ isOn: this.store.form.notify })
.onChange(v => this.store.form.notify = v)
Button("提交")
.onClick(() => {
if (this.store.validateAll()) {
console.log('提交成功', this.store.form)
}
})
}
.padding(16)
}
errorText(field: string) {
const msg = this.store.form.errors[field]
if (msg) {
Text(msg).fontColor(Color.Red).fontSize(12)
}
}
}
七、为什么这种表单结构"不容易烂"?
因为它满足了 5 个关键原则:
-
状态集中(Form Model)
-
校验解耦(Validator)
-
逻辑统一(Store)
-
UI 纯展示
-
规则可扩展
八、进阶:实时校验 vs 提交校验
你可以轻松控制策略:
| 场景 | 做法 |
|---|---|
| 实时校验 | onChange 调 validateField |
| 失焦校验 | onBlur 调 validateField |
| 提交校验 | validateAll |
📌 不需要改 UI 结构
九、复杂表单常见"灾难级写法"(避坑)
❌ 校验写在 onClick 里
一多就失控
❌ 每个字段一个 @Local error
状态爆炸
❌ UI 直接写正则
维护噩梦
十、这一篇你真正学会了什么?
你已经掌握:
✔ HarmonyOS 表单建模思维
✔ 表单校验体系设计
✔ UI / 逻辑 / 规则解耦
✔ 可扩展的表单架构
这套方法:
不仅适用于 HarmonyOS,也适用于 Vue / React / Flutter
结语
表单写得好不好,是区分"Demo 开发者"和"工程型开发者"的分水岭。
能走到这一篇,你已经明显进入 中高级 HarmonyOS 开发者的轨道了。