HarmonyOS7 Stepper 式流程页更稳:一步只解决一个问题

文章目录
前言
实名认证、开户、报销提交这类页面,如果把所有输入一次性摆出来,用户压力会很大。姓名、证件号、照片、协议确认、提交按钮全在一屏里,出错时也不好定位。
Stepper 式流程更适合这类任务。一步只处理一件事,完成后再进入下一步,用户知道自己现在在哪里,也知道下一步要做什么。
流程页稳定的关键,是每一步都有进入条件和完成条件。
为什么这个问题经常被写乱

Stepper 式流程页更稳 这类内容很容易被写成“代码能跑就算讲完了”,但对初学者来说,这恰恰是最不够的地方。真正让人卡住的,往往不是某个组件名记不住,而是不知道这段代码为什么要这样拆、状态为什么要这样放、以后需求变化时应该从哪里改。
所以这篇文章不只想给你一个能跑的例子,更想把背后的判断过程讲清楚。你只要把这个判断过程吃透,后面自己改页面、补需求、查问题时,心里会稳很多。
先拆步骤,再写页面
流程页不要直接从 UI 开始写。先把步骤、内容和完成条件列清楚。
| 步骤 | 内容 | 完成条件 |
|---|---|---|
| 1 | 填写身份信息 | 姓名和证件号不为空 |
| 2 | 上传证件 | 已选择文件 |

| 3 | 确认提交 | 勾选确认 |
这张表决定了后面的状态设计。页面只是在不同步骤展示不同内容,核心逻辑是 currentStep 和 canNext()。
先把页面目标想清楚
在真正写代码之前,先别急着盯着 API。更有用的做法是先想清楚:这个页面到底想解决什么问题,用户最在意的反馈是什么,哪些状态必须一直保持一致。
当你先把这条主线想明白,再回头看组件和状态设计,很多选择都会顺理成章。对小白来说,这一步尤其重要,因为它能帮你从“照着抄”慢慢过渡到“看得懂、改得动”。
完整 ArkTS 示例
interface VerifyStep39 {
id: number
title: string
}
@Entry
@Component
struct StepperVerifyPage39 {
@State currentStep: number = 0
@State realName: string = ''
@State cardNo: string = ''
@State hasFile: boolean = false
@State confirmed: boolean = false
private steps: VerifyStep39[] = [
{ id: 0, title: '身份信息' },
{ id: 1, title: '证件上传' },
{ id: 2, title: '确认提交' }
]
canNext(): boolean {
if (this.currentStep === 0) {
return this.realName.length > 0 && this.cardNo.length > 0
}
if (this.currentStep === 1) {
return this.hasFile
}
return this.confirmed
}
next(): void {
if (!this.canNext()) {
return
}
if (this.currentStep < 2) {
this.currentStep += 1
}
}
build() {
Column({ space: 16 }) {
Text('实名认证')
.fontSize(26)
.fontWeight(FontWeight.Bold)
.width('100%')
Row({ space: 8 }) {
ForEach(this.steps, (item: VerifyStep39) => {
Text(item.title)
.fontSize(13)
.fontColor(this.currentStep === item.id ? '#FFFFFF' : '#666666')
.padding({ left: 10, right: 10, top: 6, bottom: 6 })
.backgroundColor(this.currentStep === item.id ? '#2F6FED' : '#FFFFFF')
.borderRadius(14)
}, (item: VerifyStep39) => item.id.toString())
}
.width('100%')
Column({ space: 12 }) {
if (this.currentStep === 0) {
TextInput({ placeholder: '请输入姓名', text: this.realName })
.onChange((value: string) => { this.realName = value })
TextInput({ placeholder: '请输入证件号', text: this.cardNo })
.onChange((value: string) => { this.cardNo = value })
} else if (this.currentStep === 1) {
Text(this.hasFile ? '已选择身份证照片' : '请上传身份证照片')
.fontSize(16)
Button(this.hasFile ? '重新选择' : '选择文件')
.onClick(() => { this.hasFile = true })
} else {
Text('请确认信息真实有效,提交后进入审核。')
.fontSize(15)
.fontColor('#666666')
Row() {
Checkbox()
.select(this.confirmed)
.onChange((value: boolean) => { this.confirmed = value })
Text('我确认以上信息无误')
.fontSize(14)
.margin({ left: 8 })
}
}
}
.padding(16)
.width('100%')
.backgroundColor('#FFFFFF')
.borderRadius(12)
Row() {
Button('上一步')
.enabled(this.currentStep > 0)
.onClick(() => { this.currentStep -= 1 })
Blank()
Button(this.currentStep === 2 ? '提交' : '下一步')
.enabled(this.canNext())
.onClick(() => this.next())
}
.width('100%')
}
.padding(16)
.width('100%')
.height('100%')
.backgroundColor('#F6F7F9')
}
}
currentStep 是唯一位置来源
流程页最怕多个布尔值控制显示,比如 showUserInfo、showUpload、showConfirm。一旦状态没同步,就可能两个步骤同时显示,或者都不显示。
示例只用 currentStep 表示当前位置。当前是 0 就展示身份信息,是 1 就展示证件上传,是 2 就展示确认提交。
位置来源只有一个,页面就不会互相打架。
canNext() 要同时服务按钮和逻辑
按钮的 enabled(this.canNext()) 是体验层,能让用户知道当前步骤还没完成。
但 next() 里仍然要再调用一次 canNext()。这不是重复,而是底线。以后如果某个快捷入口直接调用 next(),或者异步状态在点击前后发生变化,方法内部校验能兜住问题。
按钮状态负责提示,方法内部校验负责保证流程不被绕过。
上一步也要考虑边界
示例里“上一步”按钮通过 .enabled(this.currentStep > 0) 禁用,避免从第一步继续往前退。
如果要写得更严谨,可以把上一步也封装成方法:
previous(): void {
if (this.currentStep > 0) {
this.currentStep -= 1
}
}
流程页越复杂,越建议把前进、后退、提交都收成方法。UI 只绑定动作,不直接改很多状态。
Stepper 页面要考虑可恢复
实名认证、开户、报销这类流程不一定一次完成。用户可能切到后台,也可能上传失败后回来重试。
| 中断点 | 建议处理 | 用户体验 |
|---|---|---|
| 填完第一步退出 | 保存草稿 | 不用重填 |
| 上传文件失败 | 停留在第二步 | 知道哪里失败 |
| 最后提交失败 | 保留确认页 | 可以重试 |
| 审核中返回 | 展示结果状态 | 不重复提交 |
示例把字段都放在页面状态里,页面切步骤时不会丢。真实项目可以在每一步完成后保存草稿。
不要把提交状态塞进步骤里
currentStep 表示流程位置,submitting 表示是否正在提交,它们是两件事。
如果把提交中写成一个新的步骤,比如 currentStep = 3,后面失败、重试、返回确认页都会变麻烦。更好的做法是保留 currentStep === 2,再加 submitting 和 submitError。
状态越清楚,流程越好维护。
新手最容易踩的坑
这一类示例最容易让人产生错觉:界面出来了,就以为已经掌握了。其实真正容易出问题的地方,通常都在效果之外,比如状态有没有收拢、失败后怎么兜底、以后要扩展时会不会牵一发动全身。
所以你练这篇内容时,别只看“现在能不能跑”,还要继续看“以后好不好改”。能把这个习惯养起来,你写出来的页面会比单纯照着示例拼出来的页面稳很多。
放进真实项目还要补什么
示例代码的重点是把核心思路讲明白,所以很多工程化细节会故意省掉。真正落到项目里时,你通常还要继续补接口联动、异常处理、边界保护、资源抽离,以及和其他页面状态之间的配合。
比较稳的做法是分三步走:先把结构和职责立住,再把真实业务接进去,最后再优化视觉和交互体验。这样改出来的页面不只是“能演示”,而是真的更接近可以长期维护的业务代码。
写在最后
HarmonyOS7 写这类流程页,先把步骤、完成条件和状态边界定好,再写 UI。这样校验、回退、失败重试都会稳很多。
更多推荐

所有评论(0)