🎯 前言

在移动应用开发中,用户认证系统是核心功能之一。本文将详细介绍如何在HarmonyOS中实现一个功能完整、设计精美的登录注册系统,包括用户注册、登录验证、记住密码等核心功能,以及使用preferences进行本地数据存储的最佳实践。

📱 功能需求分析

我们的登录注册系统需要实现以下核心功能:

1. 用户注册

  • 用户名、密码、确认密码输入
  • 表单验证(字段完整性、密码一致性、密码强度)
  • 用户数据本地存储

2. 用户登录

  • 用户名和密码验证
  • 与注册数据的匹配校验
  • 登录状态管理

3. 记住密码

  • 用户选择是否记住登录信息
  • 自动填充用户名和密码
  • 数据持久化存储

4. UI设计

  • 美观的渐变背景
  • 响应式布局设计
  • 统一的视觉风格

🏗️ 系统架构设计

1. 页面结构

启动页 → 登录页 → 主页
    ↓
注册页 ← → 登录页

2. 数据存储架构

preferences/
├── user_data/          # 注册用户数据
│   ├── username        # 用户名
│   └── password        # 密码
└── login_data/         # 登录状态数据
    ├── username        # 记住的用户名
    ├── password        # 记住的密码
    └── rememberPassword # 是否记住密码

💻 核心代码实现

1. 注册页面实现

1.1 页面结构定义
@Entry
@Component
struct RegisterPage {
  @State username: string = ''
  @State password: string = ''
  @State confirmPassword: string = ''
  @State isLoading: boolean = false
  private preferencesHelper: preferences.Preferences | null = null
}

关键点解析:

  • @Entry:标识这是应用的入口页面
  • @Component:声明这是一个自定义组件
  • @State:响应式状态管理,数据变化时UI自动更新
  • private preferencesHelper:用户首选项,用于数据存储
1.2 用户首选项初始化
async initPreferences() {
  try {
    const context = this.getUIContext().getHostContext() as Context
    this.preferencesHelper = await preferences.getPreferences(context, 'user_data')
  } catch (error) {
    console.error('初始化偏好设置失败:', error)
  }
}

技术要点:

  • 使用getUIContext().getHostContext()获取应用上下文
  • 创建user_data命名空间的偏好设置实例
  • 完善的错误处理机制
1.3 用户数据保存
async saveUserData() {
  if (this.preferencesHelper) {
    try {
      // 保存用户名和密码
      await this.preferencesHelper.put('username', this.username)
      await this.preferencesHelper.put('password', this.password)
      await this.preferencesHelper.flush()
      console.error('--------------', `用户数据保存成功:用户名=${this.username}`)
    } catch (error) {
      console.error('保存用户数据失败:', error)
    }
  }
}

存储机制:

  • put():存储键值对数据
  • flush():立即将数据写入磁盘
  • 异步操作确保数据完整性
1.4 表单验证逻辑
handleRegister() {
  if (!this.username.trim() || !this.password.trim() || !this.confirmPassword.trim()) {
    promptAction.showToast({
      message: '请填写所有字段',
      duration: 2000
    })
    return
  }

  if (this.password !== this.confirmPassword) {
    promptAction.showToast({
      message: '两次输入的密码不一致',
      duration: 2000
    })
    return
  }

  if (this.password.length < 6) {
    promptAction.showToast({
      message: '密码长度至少6位',
      duration: 2000
    })
    return
  }

  // 执行注册逻辑...
}

验证规则:

  • 字段完整性检查
  • 密码一致性验证
  • 密码强度要求(至少6位)

2. 登录页面实现

2.1 记住密码功能
async initPreferences() {
  try {
    const context = this.getUIContext().getHostContext() as Context
    this.preferencesHelper = await preferences.getPreferences(context, 'login_data')
    
    // 读取保存的用户名和密码(记住密码功能)
    const savedUsername = await this.preferencesHelper.get('username', '')
    const savedPassword = await this.preferencesHelper.get('password', '')
    const savedRemember = await this.preferencesHelper.get('rememberPassword', false)
    
    if (savedRemember && savedUsername && savedPassword) {
      this.username = savedUsername as string
      this.password = savedPassword as string
      this.rememberPassword = savedRemember as boolean
      console.error('--------------', `读取到记住密码的数据:用户名=${this.username},密码=${this.password}`)
    }
  } catch (error) {
    console.error('--------------', `初始化偏好设置失败${error}`)
  }
}

功能特点:

  • 独立的login_data命名空间
  • 自动填充已保存的用户信息
  • 状态持久化管理
2.2 用户凭据验证
async validateUserCredentials(): Promise<boolean> {
  try {
    // 读取注册时保存的用户数据
    const userPreferences = await preferences.getPreferences(
      this.getUIContext().getHostContext() as Context, 
      'user_data'
    )
    
    const savedUsername = await userPreferences.get('username', '')
    const savedPassword = await userPreferences.get('password', '')
    
    console.error('--------------', `验证用户:输入用户名=${this.username},保存用户名=${savedUsername}`)
    console.error('--------------', `验证用户:输入密码=${this.password},保存密码=${savedPassword}`)
    
    // 检查用户名和密码是否匹配
    if (savedUsername === this.username && savedPassword === this.password) {
      console.error('--------------', '用户验证成功')
      return true
    } else {
      console.error('--------------', '用户验证失败')
      return false
    }
  } catch (error) {
    console.error('验证用户凭据失败:', error)
    return false
  }
}

验证机制:

  • user_data读取注册信息
  • 与用户输入进行精确匹配
  • 完善的错误处理和日志记录
2.3 登录流程控制
async handleLogin() {
  if (!this.username.trim() || !this.password.trim()) {
    promptAction.showToast({
      message: '请输入用户名和密码',
      duration: 2000
    })
    return
  }

  this.isLoading = true

  try {
    // 验证用户名和密码
    const isValid = await this.validateUserCredentials()
    
    if (isValid) {
      // 保存登录数据(记住密码功能)
      await this.saveLoginData()

      // 登录成功后跳转到主页
      promptAction.showToast({
        message: '登录成功!',
        duration: 2000
      })

      // 跳转到主页
      setTimeout(() => {
        router.pushUrl({ url: 'pages/Index' })
      }, 2000)
    } else {
      promptAction.showToast({
        message: '用户名或密码错误',
        duration: 2000
      })
    }
  } catch (error) {
    console.error('登录验证失败:', error)
    promptAction.showToast({
      message: '登录失败,请重试',
      duration: 2000
    })
  } finally {
    this.isLoading = false
  }
}

流程特点:

  • 完整的输入验证
  • 异步用户验证
  • 状态管理和错误处理
  • 用户体验优化

🎨 UI设计实现

1. 渐变背景设计

.linearGradient({
  direction: GradientDirection.Bottom,
  colors: [
    [0x667eea, 0.0],    // 淡蓝色
    [0x764ba2, 0.5],    // 淡紫色
    [0xf093fb, 1.0]     // 淡粉色
  ]
})

设计理念:

  • 使用柔和的渐变色彩,营造温馨舒适的视觉体验
  • 从淡蓝到淡紫再到淡粉,层次丰富
  • 与整体应用风格保持一致

2. 输入框设计

TextInput({ placeholder: '请输入用户名', text: this.username })
  .width('100%')
  .height(50)
  .backgroundColor('#ffffff')
  .borderRadius(12)
  .padding({ left: 16, right: 16 })
  .fontColor('#333333')
  .placeholderColor('#999999')
  .onChange((value: string) => {
    this.username = value
  })

设计特点:

  • 纯白色背景配深色文字,对比度适中
  • 圆角设计,现代感十足
  • 合理的内边距,提升用户体验

3. 按钮设计

Button('登录', { type: ButtonType.Capsule })
  .width('100%')
  .height(50)
  .backgroundColor('#ffffff')
  .fontColor('#667eea')
  .fontSize(16)
  .fontWeight(FontWeight.Medium)
  .borderRadius(12)

设计优势:

  • 白色背景在渐变背景上非常突出
  • 淡蓝色文字与背景渐变的顶部颜色呼应
  • 统一的视觉风格和交互体验

🔒 数据安全与隐私

1. 数据分离存储

  • 注册数据:存储在user_data命名空间
  • 登录状态:存储在login_data命名空间
  • 数据隔离:避免数据混淆和安全隐患

2. 本地存储优势

  • 隐私保护:用户数据不离开设备
  • 离线可用:无需网络连接即可使用
  • 响应速度:本地数据读取速度快

3. 数据完整性

  • 异步操作:确保数据写入完成
  • 错误处理:完善的异常处理机制
  • 状态管理:UI状态与数据状态同步

🚀 性能优化策略

1. 异步操作优化

// 使用async/await确保操作顺序
async initPreferences() {
  try {
    const context = this.getUIContext().getHostContext() as Context
    this.preferencesHelper = await preferences.getPreferences(context, 'user_data')
  } catch (error) {
    console.error('初始化偏好设置失败:', error)
  }
}

2. 状态管理优化

  • 使用@State装饰器实现响应式更新
  • 避免不必要的重渲染
  • 合理的组件生命周期管理

3. 用户体验优化

  • 加载状态指示器
  • 友好的错误提示
  • 平滑的页面跳转



## 📱 适配与兼容性

### 1. 安全区域适配
```typescript
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])

🎉 总结

通过本文的详细介绍,我们实现了一个功能完整、设计精美的HarmonyOS登录注册系统。关键成就包括:

1. 技术亮点

  • 完整的用户认证流程
  • 本地数据存储与管理
  • 响应式UI设计
  • 完善的错误处理

2. 用户体验

  • 直观的操作流程
  • 美观的视觉设计
  • 流畅的交互体验
  • 智能的记住密码功能

3. 代码质量

  • 清晰的架构设计
  • 规范的代码风格
  • 完善的注释文档
  • 可维护的代码结构

4. 安全特性

  • 数据分离存储
  • 本地数据保护
  • 输入验证机制
  • 异常处理完善

这个系统不仅满足了基本的登录注册需求,还在用户体验、代码质量和安全性方面有所提升,为HarmonyOS应用开发提供了完整的用户认证解决方案。

📚 相关资源

📁 项目文件结构

Demo/
├── entry/
│   └── src/
│       └── main/
│           └── ets/
│               └── pages/
│                   ├── SplashPage.ets      # 启动页面
│                   ├── LoginPage.ets       # 登录页面
│                   ├── RegisterPage.ets    # 注册页面
│                   └── Index.ets        # 主页
│           └── resources/
│               └── base/
│                   └── profile/
│                       └── main_pages.json # 页面配置
└── README.md                               # 项目说明文档

💻 完整代码实现

1. 启动页面 (SplashPage.ets)

import { router } from '@kit.ArkUI'

@Entry
@Component
struct SplashPage {
  @State countdown: number = 3
  @State isCounting: boolean = true
  private timer: number = -1

  aboutToAppear() {
    this.startCountdown()
  }

  aboutToDisappear() {
    if (this.timer !== -1) {
      clearInterval(this.timer)
    }
  }

  startCountdown() {
    this.timer = setInterval(() => {
      if (this.countdown > 0) {
        this.countdown--
      } else {
        this.isCounting = false
        clearInterval(this.timer)
        this.navigateToLogin()
      }
    }, 1000)
  }

  navigateToLogin() {
    router.replaceUrl({
      url: 'pages/LoginPage'
    })
  }

  build() {
    Stack() {
      // 背景渐变 - 使用更柔和的配色
      Column()
        .width('100%')
        .height('100%')
        .linearGradient({
          direction: GradientDirection.Bottom,
          colors: [
            [0x667eea, 0.0], // 淡蓝色
            [0x764ba2, 0.5], // 淡紫色
            [0xf093fb, 1.0]// 淡粉色
          ]
        })
        .expandSafeArea()

      // 右上角倒计时和跳转文字
      Row() {
        Text(`${this.countdown}s | 跳转`)
          .fontSize(14)
          .fontColor('#ffffff')        // 深色文字
          .fontWeight(FontWeight.Medium)
          .backgroundColor('#20ffffff')   // 纯白色背景
          .padding({
            left: 14,
            right: 14,
            top: 8,
            bottom: 8
          })
          .borderRadius(20)
          .shadow({
            radius: 8,
            color: '#00000020',
            offsetX: 0,
            offsetY: 2
          })
      }
      .position({ x: '73%', y: '5%' })

      // 主要内容
      Column() {
        // Logo区域
        Column() {
          Image($r('app.media.startIcon'))
            .width(120)
            .height(120)
            .margin({ bottom: 20 })

          Text('HarmonyOS')
            .fontSize(32)
            .fontWeight(FontWeight.Bold)
            .fontColor('#ffffff')      // 白色文字
            .margin({ bottom: 8 })

          Text('你好   世界')
            .fontSize(18)
            .fontColor('#ffffff')      // 白色文字
            .opacity(0.9)
        }
        .alignItems(HorizontalAlign.Center)
        .margin({ top: 200 })
      }
      .width('100%')
      .alignItems(HorizontalAlign.Center)
    }
    .width('100%')
    .height('100%')
  }
}

2. 登录页面 (LoginPage.ets)

import preferences from '@ohos.data.preferences'
import { promptAction, router } from '@kit.ArkUI'

@Entry
@Component
struct LoginPage {
  @State username: string = ''
  @State password: string = ''
  @State rememberPassword: boolean = false
  @State isLoading: boolean = false
  private preferencesHelper: preferences.Preferences | null = null

  aboutToAppear() {
    this.initPreferences()
  }

    async initPreferences() {
    try {
      const context = this.getUIContext().getHostContext() as Context
      this.preferencesHelper = await preferences.getPreferences(context, 'login_data')
      
      // 读取保存的用户名和密码(记住密码功能)
      const savedUsername = await this.preferencesHelper.get('username', '')
      const savedPassword = await this.preferencesHelper.get('password', '')
      const savedRemember = await this.preferencesHelper.get('rememberPassword', false)
      
      if (savedRemember && savedUsername && savedPassword) {
        this.username = savedUsername as string
        this.password = savedPassword as string
        this.rememberPassword = savedRemember as boolean
        console.error('--------------', `读取到记住密码的数据:用户名=${this.username},密码=${this.password}`)
      } else {
        console.error('--------------', `没有记住密码的数据`)
      }
    } catch (error) {
      console.error('--------------', `初始化偏好设置失败${error}`)
    }
  }

  async saveLoginData() {
    if (this.preferencesHelper) {
      try {
        if (this.rememberPassword) {
          await this.preferencesHelper.put('username', this.username)
          await this.preferencesHelper.put('password', this.password)
          await this.preferencesHelper.put('rememberPassword', true)
        } else {
          await this.preferencesHelper.delete('username')
          await this.preferencesHelper.delete('password')
          await this.preferencesHelper.put('rememberPassword', false)
        }
        await this.preferencesHelper.flush()
      } catch (error) {
        console.error('保存登录数据失败:', error)
      }
    }
  }

  async handleLogin() {
    if (!this.username.trim() || !this.password.trim()) {
      promptAction.showToast({
        message: '请输入用户名和密码',
        duration: 2000
      })
      return
    }

    this.isLoading = true

    try {
      // 验证用户名和密码
      const isValid = await this.validateUserCredentials()
      
      if (isValid) {
        // 保存登录数据(记住密码功能)
        await this.saveLoginData()

        // 登录成功后跳转到主页
        promptAction.showToast({
          message: '登录成功!',
          duration: 2000
        })

        // 跳转到主页
        setTimeout(() => {
          router.pushUrl({ url: 'pages/HomePage' })
        }, 2000)
      } else {
        promptAction.showToast({
          message: '用户名或密码错误',
          duration: 2000
        })
      }
    } catch (error) {
      console.error('登录验证失败:', error)
      promptAction.showToast({
        message: '登录失败,请重试',
        duration: 2000
      })
    } finally {
      this.isLoading = false
    }
  }

  async validateUserCredentials(): Promise<boolean> {
    try {
      // 读取注册时保存的用户数据
      const userPreferences = await preferences.getPreferences(
        this.getUIContext().getHostContext() as Context, 
        'user_data'
      )
      
      const savedUsername = await userPreferences.get('username', '')
      const savedPassword = await userPreferences.get('password', '')
      
      console.error('--------------', `验证用户:输入用户名=${this.username},保存用户名=${savedUsername}`)
      console.error('--------------', `验证用户:输入密码=${this.password},保存密码=${savedPassword}`)
      
      // 检查用户名和密码是否匹配
      if (savedUsername === this.username && savedPassword === this.password) {
        console.error('--------------', '用户验证成功')
        return true
      } else {
        console.error('--------------', '用户验证失败')
        return false
      }
    } catch (error) {
      console.error('验证用户凭据失败:', error)
      return false
    }
  }

  navigateToRegister() {
    router.pushUrl({
      url: 'pages/RegisterPage'
    })
  }

  build() {
    Column() {
      // 顶部返回按钮
      Row() {
        Button({ type: ButtonType.Circle }) {
          Image($r('app.media.ic_back'))
            .width(20)
            .height(20)
            .fillColor(Color.White)
        }
        .width(40)
        .height(40)
        .backgroundColor('#667eea')
        .onClick(() => {
          router.back()
        })

        Text('登录')
          .fontSize(20)
          .fontWeight(FontWeight.Bold)
          .fontColor(Color.White)
          .margin({ left: 16 })
      }
      .width('100%')
      .padding({ left: 20, right: 20, top: 20 })
      .justifyContent(FlexAlign.Start)

      // 主要内容
      Column() {
        // 标题
        Column() {
          Text('欢迎回来')
            .fontSize(32)
            .fontWeight(FontWeight.Bold)
            .fontColor(Color.White)
            .margin({ bottom: 8 })

          Text('请登录您的账户')
            .fontSize(16)
            .fontColor(Color.White)
            .opacity(0.9)
        }
        .alignItems(HorizontalAlign.Start)
        .margin({ top: 80, bottom: 60 })
        .padding({ left: 40, right: 40 })

        // 登录表单
        Column() {
          // 用户名输入框
          Column() {
            Text('用户名')
              .fontSize(14)
              .fontColor(Color.White)
              .fontWeight(FontWeight.Medium)
              .margin({ bottom: 8 })
              .width('100%')

            TextInput({ placeholder: '请输入用户名', text: this.username })
              .width('100%')
              .height(50)
              .backgroundColor('#ffffff')
              .borderRadius(12)
              .padding({ left: 16, right: 16 })
              .fontColor('#333333')
              .placeholderColor('#999999')
              .onChange((value: string) => {
                this.username = value
              })
          }
          .margin({ bottom: 24 })

          // 密码输入框
          Column() {
            Text('密码')
              .fontSize(14)
              .fontColor(Color.White)
              .fontWeight(FontWeight.Medium)
              .margin({ bottom: 8 })
              .width('100%')

            TextInput({ placeholder: '请输入密码', text: this.password })
              .width('100%')
              .height(50)
              .backgroundColor('#ffffff')
              .borderRadius(12)
              .padding({ left: 16, right: 16 })
              .fontColor('#333333')
              .placeholderColor('#999999')
              .type(InputType.Password)
              .onChange((value: string) => {
                this.password = value
              })
          }
          .margin({ bottom: 24 })

          // 记住密码选项
          Row() {
            Toggle({ type: ToggleType.Checkbox, isOn: this.rememberPassword })
              .onChange((isOn: boolean) => {
                this.rememberPassword = isOn
              })

            Text('记住密码')
              .fontSize(14)
              .fontColor(Color.White)
              .margin({ left: 8 })
          }
          .width('100%')
          .justifyContent(FlexAlign.Start)
          .margin({ bottom: 32 })

          // 登录按钮
          Button('登录', { type: ButtonType.Capsule })
            .width('100%')
            .height(50)
            .backgroundColor('#ffffff')
            .fontColor('#667eea')
            .fontSize(16)
            .fontWeight(FontWeight.Medium)
            .borderRadius(12)
            .onClick(() => {
              this.handleLogin()
            })
            .enabled(!this.isLoading)

          if (this.isLoading) {
            LoadingProgress()
              .color('#667eea')
              .width(20)
              .height(20)
              .margin({ top: 16 })
          }

          // 注册链接
          Row() {
            Text('还没有账户?')
              .fontSize(14)
              .fontColor(Color.White)
              .opacity(0.8)

            Text('立即注册')
              .fontSize(14)
              .fontColor('#ffffff')
              .fontWeight(FontWeight.Medium)
              .onClick(() => {
                this.navigateToRegister()
              })
          }
          .margin({ top: 24 })
        }
        .width('100%')
        .padding({ left: 40, right: 40 })
      }
      .layoutWeight(1)
      .width('100%')
    }
    .width('100%')
    .height('100%')
    .linearGradient({
      direction: GradientDirection.Bottom,
      colors: [
        [0x667eea, 0.0], // 淡蓝色
        [0x764ba2, 0.5], // 淡紫色
        [0xf093fb, 1.0]// 淡粉色
      ]
    })
    .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
  }
}

3. 注册页面 (RegisterPage.ets)

import { promptAction, router } from '@kit.ArkUI'
import preferences from '@ohos.data.preferences'

@Entry
@Component
struct RegisterPage {
  @State username: string = ''
  @State password: string = ''
  @State confirmPassword: string = ''
  @State isLoading: boolean = false
  private preferencesHelper: preferences.Preferences | null = null

  aboutToAppear() {
    this.initPreferences()
  }

  async initPreferences() {
    try {
      const context = this.getUIContext().getHostContext() as Context
      this.preferencesHelper = await preferences.getPreferences(context, 'user_data')
    } catch (error) {
      console.error('初始化偏好设置失败:', error)
    }
  }

  async saveUserData() {
    if (this.preferencesHelper) {
      try {
        // 保存用户名和密码
        await this.preferencesHelper.put('username', this.username)
        await this.preferencesHelper.put('password', this.password)
        await this.preferencesHelper.flush()
        console.error('--------------', `用户数据保存成功:用户名=${this.username}`)
      } catch (error) {
        console.error('保存用户数据失败:', error)
      }
    }
  }

  handleRegister() {
    if (!this.username.trim() || !this.password.trim() || !this.confirmPassword.trim()) {
      promptAction.showToast({
        message: '请填写所有字段',
        duration: 2000
      })
      return
    }

    if (this.password !== this.confirmPassword) {
      promptAction.showToast({
        message: '两次输入的密码不一致',
        duration: 2000
      })
      return
    }

    if (this.password.length < 6) {
      promptAction.showToast({
        message: '密码长度至少6位',
        duration: 2000
      })
      return
    }

    this.isLoading = true
    
    // 模拟注册请求
    setTimeout(async () => {
      this.isLoading = false
      
      // 保存用户数据到本地
      await this.saveUserData()
      
      promptAction.showToast({
        message: '注册成功!',
        duration: 2000
      })
      
      // 注册成功后返回登录页
      setTimeout(() => {
        router.back()
      }, 2000)
    }, 1500)
  }

  build() {
    Column() {
      // 顶部返回按钮
      Row() {
        Button({ type: ButtonType.Circle }) {
          Image($r('app.media.ic_back'))
            .width(20)
            .height(20)
            .fillColor(Color.White)
        }
        .width(40)
        .height(40)
        .backgroundColor('#667eea')
        .onClick(() => {
          router.back()
        })
        
        Text('注册')
          .fontSize(20)
          .fontWeight(FontWeight.Bold)
          .fontColor(Color.White)
          .margin({ left: 16 })
      }
      .width('100%')
      .padding({ left: 20, right: 20, top: 20 })
      .justifyContent(FlexAlign.Start)

      // 主要内容
      Column() {
        // 标题
        Column() {
          Text('创建账户')
            .fontSize(32)
            .fontWeight(FontWeight.Bold)
            .fontColor(Color.White)
            .margin({ bottom: 8 })
          
          Text('请填写以下信息完成注册')
            .fontSize(16)
            .fontColor(Color.White)
            .opacity(0.9)
        }
        .alignItems(HorizontalAlign.Start)
        .margin({ top: 60, bottom: 50 })
        .padding({ left: 40, right: 40 })

        // 注册表单
        Column() {
          // 用户名输入框
          Column() {
            Text('用户名')
              .fontSize(14)
              .fontColor(Color.White)
              .fontWeight(FontWeight.Medium)
              .margin({ bottom: 8 })
              .width('100%')
            
            TextInput({ placeholder: '请输入用户名', text: this.username })
              .width('100%')
              .height(50)
              .backgroundColor('#ffffff')
              .borderRadius(12)
              .padding({ left: 16, right: 16 })
              .fontColor('#333333')
              .placeholderColor('#999999')
              .onChange((value: string) => {
                this.username = value
              })
          }
          .margin({ bottom: 24 })

          // 密码输入框
          Column() {
            Text('密码')
              .fontSize(14)
              .fontColor(Color.White)
              .fontWeight(FontWeight.Medium)
              .margin({ bottom: 8 })
              .width('100%')
            
            TextInput({ placeholder: '请输入密码(至少6位)', text: this.password })
              .width('100%')
              .height(50)
              .backgroundColor('#ffffff')
              .borderRadius(12)
              .padding({ left: 16, right: 16 })
              .fontColor('#333333')
              .placeholderColor('#999999')
              .type(InputType.Password)
              .onChange((value: string) => {
                this.password = value
              })
          }
          .margin({ bottom: 24 })

          // 确认密码输入框
          Column() {
            Text('确认密码')
              .fontSize(14)
              .fontColor(Color.White)
              .fontWeight(FontWeight.Medium)
              .margin({ bottom: 8 })
              .width('100%')
            
            TextInput({ placeholder: '请再次输入密码', text: this.confirmPassword })
              .width('100%')
              .height(50)
              .backgroundColor('#ffffff')
              .borderRadius(12)
              .padding({ left: 16, right: 16 })
              .fontColor('#333333')
              .placeholderColor('#999999')
              .type(InputType.Password)
              .onChange((value: string) => {
                this.confirmPassword = value
              })
          }
          .margin({ bottom: 32 })

          // 注册按钮
          Button('注册', { type: ButtonType.Capsule })
            .width('100%')
            .height(50)
            .backgroundColor('#ffffff')
            .fontColor('#667eea')
            .fontSize(16)
            .fontWeight(FontWeight.Medium)
            .borderRadius(12)
            .onClick(() => {
              this.handleRegister()
            })
            .enabled(!this.isLoading)

          if (this.isLoading) {
            LoadingProgress()
              .color('#667eea')
              .width(20)
              .height(20)
              .margin({ top: 16 })
          }

          // 登录链接
          Row() {
            Text('已有账户?')
              .fontSize(14)
              .fontColor(Color.White)
              .opacity(0.8)
            
            Text('立即登录')
              .fontSize(14)
              .fontColor('#ffffff')
              .fontWeight(FontWeight.Medium)
              .onClick(() => {
                router.back()
              })
          }
          .margin({ top: 24 })
        }
        .width('100%')
        .padding({ left: 40, right: 40 })
      }
      .layoutWeight(1)
      .width('100%')
    }
    .width('100%')
    .height('100%')
    .linearGradient({
      direction: GradientDirection.Bottom,
      colors: [
        [0x667eea, 0.0],    // 淡蓝色
        [0x764ba2, 0.5],    // 淡紫色
        [0xf093fb, 1.0]     // 淡粉色
      ]
    })
    .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
  }
}

5. 页面配置文件 (main_pages.json)

每个页面都需要在 main_pages.json中注册。所以我们在创建页面的时候,选择New->Page->Empet Page 来创建页面,这样系统就会自动在main_pages.json下添加,否则就只能手动添加进去

{
  "src": [
    "pages/SplashPage",
    "pages/LoginPage",
    "pages/RegisterPage",
    "pages/Index"
  ]
}

6. 项目演示效果

在这里插入图片描述

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐