
前言
密码框不是一个普通输入框换成星号那么简单。注册、改密、重置密码都需要可见性切换、强度提示、二次确认和提交禁用。我的原则是:让用户知道哪里不满足,但不要在每敲一个字符时用红字吓人。
密码体验要克制,提示足够清楚,反馈不要过度。
本文用“设置登录密码”做例子。页面目标不是把规则藏起来等用户提交失败,而是在输入过程中逐步告诉用户还差什么。

为什么这个问题经常被写乱
密码输入框的小细节 这类内容很容易被写成“代码能跑就算讲完了”,但对初学者来说,这恰恰是最不够的地方。真正让人卡住的,往往不是某个组件名记不住,而是不知道这段代码为什么要这样拆、状态为什么要这样放、以后需求变化时应该从哪里改。
所以这篇文章不只想给你一个能跑的例子,更想把背后的判断过程讲清楚。你只要把这个判断过程吃透,后面自己改页面、补需求、查问题时,心里会稳很多。
细节清单
| 细节 | 建议 |
|---|---|
| 明文切换 | 按钮文字或图标明确 |

| 强度提示 | 用规则列表表达 |
| 二次确认 | 失焦或提交前提示 |
| 提交按钮 | 不满足规则时禁用 |
实现步骤
- 密码和确认密码分开维护状态。
- 明文开关只影响输入框类型,不改密码内容。
- 密码规则拆成独立方法,供规则列表和按钮共同使用。
- 二次确认只在用户输入后参与判断,避免空输入时直接报错。
- 提交按钮只依赖
canSubmit(),不要再写重复条件。
ArkUI/ArkTS 示例
@Entry
@Component
struct PasswordInputPage {
@State password: string = ''
@State confirm: string = ''
@State visible: boolean = false
private hasLength(): boolean { return this.password.length >= 8 }
private hasNumber(): boolean { return /[0-9]/.test(this.password) }
private hasLetter(): boolean { return /[A-Za-z]/.test(this.password) }
private matched(): boolean { return this.password.length > 0 && this.password === this.confirm }
private canSubmit(): boolean { return this.hasLength() && this.hasNumber() && this.hasLetter() && this.matched() }
@Builder
RuleRow(ok: boolean, text: string) {
Row({ space: 6 }) {
Text(ok ? '✓' : '·').fontSize(14).fontColor(ok ? '#2F9E44' : '#999999')
Text(text).fontSize(13).fontColor(ok ? '#2F9E44' : '#777777')
}
}
build() {
Column({ space: 14 }) {
Text('设置登录密码').fontSize(24).fontWeight(FontWeight.Bold)
Row({ space: 8 }) {
TextInput({ text: this.password, placeholder: '请输入新密码' })
.type(this.visible ? InputType.Normal : InputType.Password)
.layoutWeight(1)
.onChange((v: string) => { this.password = v })
Button(this.visible ? '隐藏' : '显示').height(40).onClick(() => { this.visible = !this.visible })
}
TextInput({ text: this.confirm, placeholder: '再次输入密码' })
.type(this.visible ? InputType.Normal : InputType.Password)
.onChange((v: string) => { this.confirm = v })
Column({ space: 6 }) {
this.RuleRow(this.hasLength(), '至少 8 位字符')
this.RuleRow(this.hasLetter(), '包含英文字母')
this.RuleRow(this.hasNumber(), '包含数字')
this.RuleRow(this.matched(), '两次输入一致')
}
.alignItems(HorizontalAlign.Start)
.padding(12)
.backgroundColor('#F6F8FA')
.borderRadius(10)
Button('完成设置')
.width('100%')
.height(44)
.enabled(this.canSubmit())
}
.padding(16)
.backgroundColor('#FFFFFF')
.height('100%')
}
}
关键代码说明
规则方法拆开写,让强度提示和提交按钮复用同一套判断,不会出现提示说通过但按钮仍不可点。
visible 同时控制两个输入框,避免确认密码还是隐藏状态导致用户难以核对。
规则列表比单句错误更友好,用户能逐项补齐,而不是猜系统到底要什么。
规则强度取舍
| 规则 | 是否建议必填 | 原因 |
|---|---|---|
| 至少 8 位 | 建议 | 基础安全要求 |
| 字母和数字 | 建议 | 能挡住过弱密码 |
| 特殊字符 | 视业务而定 | 过强可能增加输入成本 |
| 不能包含手机号 | 高安全场景建议 | 防止明显弱密码 |
密码规则越多,越要在输入前展示。不要等用户点“完成设置”后才一次性弹出一串错误,那会让表单显得很粗糙。
常见坑
- 明文切换后不要清空输入内容。
- 确认密码和新密码要使用同一套可见性状态。
- 规则提示和按钮可用状态必须来自同一套判断。
- 不要把密码原文写入日志或调试文案。
密码规则要和按钮状态共用判断
密码页最怕“提示是一套,按钮又是一套”。用户明明看到规则都变绿了,按钮却还是不可点,或者按钮能点但提交后又报规则不满足,这种体验会让人很没耐心。
示例里把 hasLength()、hasNumber()、hasLetter()、matched() 拆成独立方法,就是为了让规则列表和 canSubmit() 共用同一批判断。这样以后规则变化,比如增加特殊字符或不能包含手机号,只需要改判断方法,不用在多个 UI 位置重复找条件。
另外,明文切换只应该影响输入展示,不应该影响密码值。确认密码也要跟着同一个 visible 状态走,否则用户核对两次输入时会很别扭。密码框越是安全相关,交互越要稳定、清楚、少惊吓。
小结
HarmonyOS7 密码框要做的是降低用户犯错成本。规则说清楚、按钮状态准确,体验就已经比很多“只给错误弹窗”的页面好。

3万+

被折叠的 条评论
为什么被折叠?



