HarmonyOS7 状态机管理复杂表单:ArkUI/ArkTS 实战拆解
前言

复杂表单真正难的不是输入框多,而是流程状态多。草稿、校验失败、提交中、已提交、被驳回如果都靠布尔值拼,很容易出现非法组合。
这篇单独聊 报销申请 这个场景。重点不是堆 API,而是用状态机约束复杂表单的草稿、校验失败、提交中和已提交流程。
为什么复杂表单总是越改越乱
因为表单一开始看上去只是几个输入框,很多人自然会先用最顺手的方式往前写:加一个 isSubmitting,再加一个 hasError,不够再补一个 isSuccess。
问题是这些布尔值前期很好加,后期却很难收。只要流程一复杂,你就会慢慢写出“既提交成功又还能编辑”“正在提交但还显示校验错误”这种别扭状态。
所以这篇文章想解决的核心,不是怎么声明一个枚举,而是怎么把表单流程真正收成一条清楚的状态线。
复杂表单别靠布尔值硬撑
报销申请这类表单会经历草稿、校验失败、提交中、已提交、被驳回。用一堆 isSubmit/isError/isEdit 很快会互相冲突,状态机更稳。
你可以先把它想成一个最简单的问题:这张表单现在到底处在哪一个阶段。只要这个问题回答不清,按钮文案、输入框可编辑性、错误提示就会开始互相打架。

实操步骤
- 先列出表单状态,而不是先写输入框。
- 每个动作只允许从指定状态进入下一个状态。
- UI 按状态决定按钮文案和可编辑性。
- 错误信息单独保存,不塞进状态枚举。
| 状态 | 可编辑 | 主按钮 |
|---|---|---|
| Draft | 是 | 提交 |
| Invalid | 是 | 重新提交 |
| Submitting | 否 | 提交中 |
| Submitted | 否 | 已提交 |
状态机不是复杂化,而是把“什么时候能做什么”写清楚。
enum FormStage {
Draft,
Invalid,
Submitting,
Submitted
}
@Entry
@Component
struct ExpenseFormPage {
@State stage: FormStage = FormStage.Draft
@State amount: string = ''
@State reason: string = ''
@State errorText: string = ''
private editable(): boolean {
return this.stage === FormStage.Draft || this.stage === FormStage.Invalid
}
private submit() {
if (!this.editable()) {
return
}
if (this.amount.trim().length === 0 || this.reason.trim().length < 4) {
this.errorText = '请填写金额,并补充至少 4 个字的报销原因'
this.stage = FormStage.Invalid
return
}
this.stage = FormStage.Submitting
this.errorText = ''
this.stage = FormStage.Submitted
}
private buttonText(): string {
if (this.stage === FormStage.Submitting) {
return '提交中'
}
if (this.stage === FormStage.Submitted) {
return '已提交'
}
return this.stage === FormStage.Invalid ? '重新提交' : '提交'
}
build() {
Column({ space: 14 }) {
Text('报销申请').fontSize(22).fontWeight(FontWeight.Bold)
TextInput({ placeholder: '报销金额', text: this.amount }).enabled(this.editable()).onChange((value: string) => this.amount = value)
TextArea({ placeholder: '报销原因', text: this.reason }).enabled(this.editable()).height(90).onChange((value: string) => this.reason = value)
if (this.errorText.length > 0) {
Text(this.errorText).fontSize(13).fontColor('#D92D20')
}
Button(this.buttonText()).enabled(this.editable()).width('100%').onClick(() => this.submit())
}.padding(16)
}
}

把关键代码一段段拆开
FormStage是唯一流程状态,避免多个布尔字段组合出非法状态。editable()统一控制输入框和按钮是否可操作。submit()只负责状态迁移,校验失败进入Invalid,成功进入Submitted。errorText单独保存,状态枚举只表达流程,不承载文案。
表单状态机要限制非法组合
复杂表单最怕多个布尔值互相打架。isSubmitting、isError、isSubmitted 同时存在时,很容易组合出“已经提交但还能编辑”“正在提交但又显示错误”的状态。状态机的价值,就是把流程收敛成一个明确阶段。
示例里的 FormStage 只表达流程,不承载错误文案。校验失败进入 Invalid,用户仍然可以编辑;提交中进入 Submitting,输入框和按钮都不可操作;提交成功进入 Submitted,页面不再允许重复提交。
放进真实项目还要补什么
真实项目里的表单,通常还会接异步提交、草稿保存、驳回重提、附件上传这些流程。只要流程一多,状态机的价值就会越来越明显,因为你终于可以明确地说出:当前是哪个阶段,允许做什么,不允许做什么。
如果后面要接接口,最好连“请求发起中”“请求失败后回到哪个状态”“成功后是否还能编辑”这些规则一起先补上。别等需求叠起来再补,到时候最容易重新滑回一堆布尔值。
写在最后
后续如果增加“被驳回”“草稿已保存”“等待审批”,也应该继续扩展状态和迁移动作,而不是再随手加布尔值。流程越复杂,越要先问清楚:当前状态下允许用户做什么。
更多推荐

所有评论(0)