鸿蒙原生开发手记:徒步迹 - 验证码登录与忘记密码

发布时间:2026/7/16 23:51:40

鸿蒙原生开发手记:徒步迹 - 验证码登录与忘记密码 鸿蒙原生开发手记徒步迹 - 验证码登录与忘记密码实现短信验证码登录和密码重置功能一、前言除了密码登录短信验证码登录和忘记密码是移动 App 的标配功能。本文在已实现的登录页基础上增加验证码登录和密码重置的能力。二、验证码登录2.1 页面实现Entry Component struct CodeLoginPage { State private phone: string ; State private code: string ; State private countdown: number 0; State private isLoading: boolean false; State private phoneError: string ; State private codeError: string ; build() { Column() { // 标题 Text(验证码登录) .fontSize(24) .fontWeight(FontWeight.Bold) .width(100%); Text(输入手机号获取验证码) .fontSize(14) .fontColor(#666) .width(100%) .margin({ top: 8 }); // 手机号输入 TextInput({ placeholder: 请输入手机号, text: this.phone }) .width(100%).height(50) .backgroundColor(#F5F5F5).borderRadius(12).padding({ left: 16 }) .type(InputType.PhoneNumber).maxLength(11) .margin({ top: 30 }) .onChange((v) { this.phone v; this.phoneError ; }); // 手机号校验提示 if (this.phoneError) { Text(this.phoneError).fontSize(12).fontColor(#F44336).width(100%).margin({ top: 4 }); } // 验证码输入 Row() { TextInput({ placeholder: 请输入验证码, text: this.code }) .layoutWeight(1) .backgroundColor(Color.Transparent) .type(InputType.Number).maxLength(6) .onChange((v) { this.code v; this.codeError ; }); Button(this.countdown 0 ? ${this.countdown}s后重发 : 获取验证码) .backgroundColor(this.countdown 0 ? #999 : #4CAF50) .borderRadius(8).height(40).fontSize(14).fontColor(Color.White) .enabled(this.countdown 0 this.phone.length 11) .onClick(() { if (this.countdown 0) this.sendCode(); }); } .width(100%).height(50) .backgroundColor(#F5F5F5).borderRadius(12).padding({ left: 16 }) .margin({ top: 16 }); // 验证码提示 if (this.codeError) { Text(this.codeError).fontSize(12).fontColor(#F44336).width(100%).margin({ top: 4 }); } // 登录按钮 Button() { if (this.isLoading) { LoadingProgress().width(24).height(24).color(Color.White); } else { Text(登录).fontSize(16).fontColor(Color.White); } } .width(100%).height(50) .backgroundColor(this.code.length 6 ? #4CAF50 : #CCC) .borderRadius(25) .margin({ top: 32 }) .enabled(this.code.length 6 !this.isLoading) .onClick(() this.handleCodeLogin()); // 切换到密码登录 Text(使用密码登录 ) .fontSize(14) .fontColor(#4CAF50) .margin({ top: 20 }) .onClick(() { router.back(); }); } .width(100%).height(100%) .padding({ left: 24, right: 24 }) .backgroundColor(Color.White); } sendCode(): void { // 模拟发送验证码 this.countdown 60; const interval setInterval(() { this.countdown--; if (this.countdown 0) clearInterval(interval); }, 1000); console.log(验证码已发送到 ${this.phone}); } handleCodeLogin(): void { this.isLoading true; setTimeout(() { this.isLoading false; AppStorage.setOrCreate(isLogged, true); router.replaceUrl({ url: pages/HomePage }); }, 1000); } }2.2 验证码后端接口参考// 发送验证码 async function sendSmsCode(phone: string): Promiseboolean { const response await apiService.request(/api/auth/send-code, POST, { phone: phone, type: login, // login / reset }); return response.code 200; } // 校验验证码 async function verifyCode(phone: string, code: string): Promisestring { const response await apiService.request(/api/auth/verify-code, POST, { phone, code, }); if (response.code 200) { return response.data.token; } throw new Error(验证码错误); }三、忘记/重置密码3.1 流程设计输入手机号 → 发送验证码 → 验证身份 → 设置新密码 → 完成3.2 实现Entry Component struct ResetPasswordPage { State private step: number 1; // 1-验证身份 2-设置密码 3-完成 State private phone: string ; State private code: string ; State private newPassword: string ; State private confirmPassword: string ; State private countdown: number 0; State private isLoading: boolean false; build() { Column() { // 步骤指示器 Row() { this.StepDot(1, 验证身份); Divider().width(40).height(2).color(this.step 2 ? #4CAF50 : #E0E0E0); this.StepDot(2, 设置密码); Divider().width(40).height(2).color(this.step 3 ? #4CAF50 : #E0E0E0); this.StepDot(3, 完成); } .width(100%) .padding({ top: 30, bottom: 40 }) .justifyContent(FlexAlign.Center); // 步骤内容 if (this.step 1) { this.StepVerifyIdentity(); } else if (this.step 2) { this.StepSetPassword(); } else { this.StepComplete(); } } .width(100%).height(100%) .padding({ left: 24, right: 24 }) .backgroundColor(Color.White); } Builder StepDot(step: number, label: string) { Column() { Text(${step}) .width(28).height(28) .fontSize(14) .fontColor(Color.White) .backgroundColor(this.step step ? #4CAF50 : #E0E0E0) .borderRadius(14) .textAlign(TextAlign.Center); Text(label) .fontSize(12) .fontColor(this.step step ? #4CAF50 : #999) .margin({ top: 4 }); } .alignItems(HorizontalAlign.Center); } Builder StepVerifyIdentity() { Column() { Text(验证身份).fontSize(20).fontWeight(FontWeight.Bold).width(100%); Text(输入注册时使用的手机号).fontSize(14).fontColor(#666).width(100%).margin({ top: 6 }); TextInput({ placeholder: 手机号, text: this.phone }) .width(100%).height(50).backgroundColor(#F5F5F5).borderRadius(12) .padding({ left: 16 }).type(InputType.PhoneNumber) .margin({ top: 24 }); Row() { TextInput({ placeholder: 验证码, text: this.code }) .layoutWeight(1).backgroundColor(Color.Transparent) .type(InputType.Number).maxLength(6); Button(this.countdown 0 ? ${this.countdown}s : 获取验证码) .backgroundColor(this.countdown 0 ? #999 : #4CAF50) .borderRadius(8).height(36).fontSize(13).fontColor(Color.White) .onClick(() { if (this.countdown 0) this.sendCode(); }); } .width(100%).height(50).backgroundColor(#F5F5F5).borderRadius(12) .padding({ left: 16 }).margin({ top: 12 }); Button(下一步).width(100%).height(50).backgroundColor(#4CAF50) .borderRadius(25).margin({ top: 30 }) .enabled(this.phone.length 11 this.code.length 6) .onClick(() { this.step 2; }); } .width(100%); } Builder StepSetPassword() { Column() { Text(设置新密码).fontSize(20).fontWeight(FontWeight.Bold).width(100%); TextInput({ placeholder: 新密码至少6位, text: this.newPassword }) .width(100%).height(50).backgroundColor(#F5F5F5).borderRadius(12) .padding({ left: 16 }).type(InputType.Password).margin({ top: 24 }); TextInput({ placeholder: 确认新密码, text: this.confirmPassword }) .width(100%).height(50).backgroundColor(#F5F5F5).borderRadius(12) .padding({ left: 16 }).type(InputType.Password).margin({ top: 12 }); Button(重置密码).width(100%).height(50).backgroundColor(#4CAF50) .borderRadius(25).margin({ top: 30 }) .enabled(this.newPassword.length 6 this.newPassword this.confirmPassword) .onClick(() { this.step 3; }); } .width(100%); } Builder StepComplete() { Column() { Text(✅).fontSize(64); Text(密码重置成功).fontSize(20).fontWeight(FontWeight.Bold).margin({ top: 16 }); Text(请使用新密码登录).fontSize(14).fontColor(#666).margin({ top: 8 }); Button(返回登录).width(100%).height(50).backgroundColor(#4CAF50) .borderRadius(25).margin({ top: 40 }) .onClick(() { router.back(); }); } .width(100%) .margin({ top: 60 }) .alignItems(HorizontalAlign.Center); } sendCode(): void { this.countdown 60; const interval setInterval(() { this.countdown--; if (this.countdown 0) clearInterval(interval); }, 1000); } }四、安全最佳实践验证码有效期通常 5 分钟限制发送频率同一手机号 60 秒内不可重复发送加密传输密码使用 HTTPS 加密传输前端脱敏手机号中间 4 位隐藏138****0000五、总结本文实现了验证码登录和密码重置两大功能采用多步骤流程设计用户体验清晰流畅。这些功能与密码登录共同组成了“徒步迹“完整的用户认证体系。下一篇文章我们将回到首页实现完整的首页布局。下一篇预告鸿蒙原生开发手记徒步迹 - 首页布局设计与Scroll滚动

相关新闻