HarmonyOS登录注册完整实现:从UI设计到数据存储的深度解析
本文介绍了在HarmonyOS中实现一个完整的登录注册系统,包含用户注册、登录验证、记住密码等核心功能。系统采用preferences进行本地数据存储,分为user_data和login_data两个命名空间管理不同数据。文章详细解析了注册页面的表单验证、数据存储机制,以及登录页面的用户凭据验证和记住密码功能实现。通过响应式状态管理、异步数据存取和健壮的错误处理,构建了一个安全可靠、用户体验良好的
🎯 前言
在移动应用开发中,用户认证系统是核心功能之一。本文将详细介绍如何在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. 项目演示效果

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

所有评论(0)