鸿蒙原生开发手记:徒步迹 - 登录注册页面与表单校验 鸿蒙原生开发手记徒步迹 - 登录注册页面与表单校验实现完整的用户认证流程包含表单验证和交互反馈一、前言登录注册是绝大多数 App 的入口功能。本文实现“徒步迹“的登录注册页面包含手机号输入、密码输入、表单校验、Loading 状态等完整交互。二、登录页面实现2.1 布局设计登录页分为三个区域标题区品牌问候语表单区手机号、密码输入操作区登录按钮、注册入口2.2 完整代码Entry Component struct LoginPage { State private phone: string ; State private password: string ; State private showPassword: boolean false; State private isLoading: boolean false; State private errorMsg: string ; build() { Column() { // 1. 标题区 Column() { Text(欢迎回来) .fontSize(28) .fontWeight(FontWeight.Bold) .fontColor($r(app.color.text_primary)) .width(100%); Text(登录徒步迹开始你的徒步之旅) .fontSize(15) .fontColor($r(app.color.text_secondary)) .width(100%) .margin({ top: 8 }); } .width(100%) .padding({ top: 60, bottom: 40 }) .alignItems(HorizontalAlign.Start); // 2. 表单区 // 手机号 TextInput({ placeholder: 请输入手机号, text: this.phone }) .width(100%) .height(50) .backgroundColor($r(app.color.background_color)) .borderRadius(12) .padding({ left: 16 }) .type(InputType.PhoneNumber) .maxLength(11) .onChange((value: string) { this.phone value; this.errorMsg ; }); // 密码带显示/隐藏切换 Row() { TextInput({ placeholder: 请输入密码, text: this.password }) .layoutWeight(1) .backgroundColor(Color.Transparent) .type(this.showPassword ? InputType.Normal : InputType.Password) .onChange((value: string) { this.password value; this.errorMsg ; }); // 密码可见切换 Text(this.showPassword ? : ️) .fontSize(20) .margin({ right: 16 }) .onClick(() { this.showPassword !this.showPassword; }); } .width(100%).height(50) .backgroundColor($r(app.color.background_color)) .borderRadius(12) .margin({ top: 16 }); // 错误提示 if (this.errorMsg) { Text(this.errorMsg) .fontSize(13) .fontColor($r(app.color.error_color)) .width(100%) .margin({ top: 8 }); } // 忘记密码 Text(忘记密码) .fontSize(14) .fontColor($r(app.color.primary_color)) .width(100%) .textAlign(TextAlign.End) .margin({ top: 12 }); // 3. 登录按钮 Button() { if (this.isLoading) { LoadingProgress().width(24).height(24).color(Color.White); } else { Text(登录).fontSize(16).fontColor(Color.White); } } .width(100%).height(50) .backgroundColor($r(app.color.primary_color)) .borderRadius(25) .margin({ top: 32 }) .enabled(this.isFormValid() !this.isLoading) .onClick(() this.handleLogin()); // 注册入口 Row() { Text(还没有账号).fontSize(14).fontColor(#999); Text(立即注册) .fontSize(14) .fontColor($r(app.color.primary_color)) .onClick(() { router.pushUrl({ url: pages/RegisterPage }); }); } .margin({ top: 24 }) .justifyContent(FlexAlign.Center); } .width(100%).height(100%) .padding({ left: 24, right: 24 }) .backgroundColor(Color.White); } // 表单校验 isFormValid(): boolean { return this.phone.length 11 this.password.length 6; } // 登录逻辑 handleLogin(): void { // 前端校验 if (!/^1[3-9]\d{9}$/.test(this.phone)) { this.errorMsg 请输入正确的手机号; return; } if (this.password.length 6) { this.errorMsg 密码至少6位; return; } this.isLoading true; // 模拟登录请求 setTimeout(() { this.isLoading false; // 登录成功保存 token AppStorage.setOrCreate(isLogged, true); router.replaceUrl({ url: pages/HomePage }); }, 1500); } }三、表单校验最佳实践3.1 手机号格式校验function validatePhone(phone: string): boolean { return /^1[3-9]\d{9}$/.test(phone); } function validatePassword(password: string): { valid: boolean; msg: string } { if (password.length 6) { return { valid: false, msg: 密码至少6位 }; } if (!/[A-Za-z]/.test(password)) { return { valid: false, msg: 密码需包含字母 }; } if (!/\d/.test(password)) { return { valid: false, msg: 密码需包含数字 }; } return { valid: true, msg: }; }3.2 实时校验使用 Watch 监听输入变化实时校验Component struct FormField { State Watch(validate) value: string ; State error: string ; Prop label: string ; Prop rules: ((v: string) string | null)[] []; validate(): void { for (let rule of this.rules) { const err rule(this.value); if (err) { this.error err; return; } } this.error ; } build() { Column() { TextInput({ placeholder: 请输入${this.label}, text: this.value }) .onChange((v) { this.value v; }); if (this.error) { Text(this.error).fontSize(12).fontColor(#F44336); } } } }四、用户体验优化4.1 Loading 状态登录按钮在请求中禁用并显示加载动画Button() { if (this.isLoading) { LoadingProgress().width(24).height(24).color(Color.White); } else { Text(登录).fontSize(16).fontColor(Color.White); } } .enabled(!this.isLoading this.isFormValid())4.2 键盘处理// 点击空白区域收起键盘 Column() .onClick(() { inputMethod.getController()?.stopInputSession(); })4.3 验证码倒计时State countdown: number 0; startCountdown(): void { this.countdown 60; const interval setInterval(() { this.countdown--; if (this.countdown 0) { clearInterval(interval); } }, 1000); }五、数据流说明用户输入 ↓ 表单校验 ← Watch 实时监听 ↓ 通过 调用 API ↓ 保存 Token → AppStorage ↓ 更新登录状态 → Provide(isLogged) ↓ 路由跳转 → HomePage六、总结登录注册页面是 App 的基础功能。本文实现了一个包含完整校验和交互反馈的登录页表单校验、Loading 状态、密码可见切换等交互都能直接用于“徒步迹“ App。下一篇文章将实现验证码登录和忘记密码功能。下一篇预告鸿蒙原生开发手记徒步迹 - 验证码登录与忘记密码

相关新闻

最新新闻

DongshanPI-D1S开发板与Melis系统开发指南

DongshanPI-D1S开发板与Melis系统开发指南

1. 认识DongshanPI-D1S开发板与Melis系统D1s是全志科技面向智能解码市场推出的高性价比AIoT芯片,采用64位RISC-V架构的平头哥C906处理器。这款芯片内置64MB DDR2内存,支持Linux系统运行,并集成了丰富的音视频编解码IP核。在实际项目中&#x…

2026/7/17 2:17:36
九宫格抽奖网页源码:原生JS+Vue双版本,含13款游戏奖品图标和3种背景

九宫格抽奖网页源码:原生JS+Vue双版本,含13款游戏奖品图标和3种背景

本文还有配套的精品资源,点击获取 简介:直接打开就能用的九宫格抽奖页面,提供HTML/CSS/JS完整结构,支持原生JavaScript和Vue两种实现方式。内置13个常见游戏类奖品图标(AWP、M4A4、P90、SG_553、MAC_10、P2000、SCA…

2026/7/17 2:17:36
Win键组合全解析:提升Windows效率的必备技巧

Win键组合全解析:提升Windows效率的必备技巧

1. Win键:被90%用户忽略的Windows效率神器每次看到同事用鼠标在开始菜单里翻找程序,或者手动点击右下角显示桌面时,我都忍不住想冲过去按住他们的手——你们知道Win键能省下多少时间吗?作为从Windows 95时代就开始折腾电脑的老鸟&…

2026/7/17 2:17:36
解决Ubuntu虚拟机与主机剪贴板同步问题

解决Ubuntu虚拟机与主机剪贴板同步问题

1. 问题现象与初步排查最近在Ubuntu虚拟机环境中工作时,遇到了一个相当恼人的问题:主机和虚拟机之间无法进行复制粘贴操作。这个问题看似简单,却直接影响工作效率。作为一名长期使用虚拟机的开发者,我决定彻底解决这个问题。首先确…

2026/7/17 2:17:36
txtai:一站式AI框架解决语义搜索与LLM编排集成难题

txtai:一站式AI框架解决语义搜索与LLM编排集成难题

如果你正在构建AI应用,可能会遇到这样的困境:想要实现语义搜索功能,却发现需要集成向量数据库;想要接入大语言模型,又得配置复杂的API服务;想要构建智能工作流,还要处理各种模型之间的数据流转。…

2026/7/17 2:17:36
Notion 早已不只是笔记软件:2026 年,它正在变成一套 AI 工作空间

Notion 早已不只是笔记软件:2026 年,它正在变成一套 AI 工作空间

📌 如果你对 Notion 的印象还停留在“一个更漂亮的在线笔记”,那么 2026 年的 Notion,可能已经和你记忆中的产品不太一样了。它仍然能写文档、搭知识库、管项目,但产品重心正在发生变化:Notion 想做的,不只…

2026/7/17 2:12:36

月新闻