登录注册页面与表单校验

鸿蒙原生开发手记:徒步迹 - 登录注册页面与表单校验

实现完整的用户认证流程,包含表单验证和交互反馈


一、前言

登录注册是绝大多数 App 的入口功能。本文实现“徒步迹“的登录注册页面,包含手机号输入、密码输入、表单校验、Loading 状态等完整交互。


二、登录页面实现

2.1 布局设计

登录页分为三个区域:

  1. 标题区:品牌问候语
  2. 表单区:手机号、密码输入
  3. 操作区:登录按钮、注册入口

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。

下一篇文章将实现验证码登录和忘记密码功能。


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

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐