47.HarmonyOS NEXT 登录模块开发教程(二):一键登录页面实现

news2025/3/13 15:37:57

温馨提示:本篇博客的详细代码已发布到 git : https://gitcode.com/nutpi/HarmonyosNext 可以下载运行哦!

HarmonyOS NEXT 登录模块开发教程(二):一键登录页面实现

文章目录

  • HarmonyOS NEXT 登录模块开发教程(二):一键登录页面实现
    • 效果预览
    • 1. 引言
    • 2. DefaultLogin 组件概述
      • 2.1 组件功能
      • 2.2 组件结构
    • 3. DefaultLogin 组件实现
      • 3.1 完整代码
      • 3.2 状态变量解析
        • 3.2.1 @Link 装饰器
        • 3.2.2 @State 装饰器
        • 3.2.3 TransitionEffect
    • 4. UI 布局详解
      • 4.1 整体布局
      • 4.2 用户信息区域
    • 总结

效果预览

1. 引言

在上一篇教程中,我们介绍了 HarmonyOS NEXT 登录模块的整体架构和模态窗口的实现原理。本篇教程将深入讲解 DefaultLogin 组件的实现,这是登录模块中最核心的组件之一,负责提供默认的一键登录页面。

一键登录是现代移动应用中常见的登录方式,它能够简化用户的登录流程,提高用户体验。在 HarmonyOS NEXT 中,我们可以通过 ArkTS 语言和声明式 UI 框架,轻松实现一个功能完善的一键登录页面。

2. DefaultLogin 组件概述

2.1 组件功能

DefaultLogin 组件主要提供以下功能:

  1. 显示用户头像和欢迎信息
  2. 展示用户手机号(预设或从系统获取)
  3. 提供服务协议阅读和同意选项
  4. 实现一键登录按钮及其交互逻辑
  5. 提供其他登录方式的入口
  6. 支持返回按钮,控制模态窗口的显示/隐藏

2.2 组件结构

部分描述
状态变量控制组件内部状态和 UI 展示
DefaultLoginPage构建一键登录页面 UI 的 Builder 函数
build 方法组件的主要构建方法,处理页面切换逻辑

3. DefaultLogin 组件实现

3.1 完整代码

import promptAction from '@ohos.promptAction';
import { OtherWaysToLogin, ReadAgreement } from './OtherWaysToLogin';

const EFFECT_DURATION = 800;
const EFFECT_OPACITY = 0.4;
const SPACE_TEN = 10;

@Component
export struct DefaultLogin {
    /**
     * isPresentInLoginView控制登录页面是否显示
     * 子组件中被@Link装饰的变量与其父组件中@State装饰的对应数据源建立双向数据绑定,详见:
     * https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-link-0000001820999565
     */
    @Link isPresentInLoginView: boolean;
    // 是否是默认一键登录方式
    @State isDefaultLogin: boolean = true;
    // 用户名
    userName: string = '18888888888';
    // 判断是否同意协议
    isConfirmed: boolean = false;
    private effect: TransitionEffect = TransitionEffect.OPACITY
        .animation({ duration: EFFECT_DURATION })
        .combine(TransitionEffect.opacity(EFFECT_OPACITY))

    // 默认一键登录方式
    @Builder
    DefaultLoginPage() {
        Column({ space: SPACE_TEN }) {
            Row({ space: SPACE_TEN }) {
                Image($r('app.media.batman'))
                    .width($r('app.integer.modalwindow_user_image_height'))
                    .height($r('app.integer.modalwindow_user_image_height'))
                Column({ space: SPACE_TEN }) {
                    Text($r('app.string.modalwindow_welcome_back'))
                        .fontWeight(FontWeight.Bold)
                        .fontSize($r('app.integer.modalwindow_font_size_mid'))
                        .fontColor(Color.Black)

                    Text($r('app.string.modalwindow_more_wonderful_after_login'))
                        .fontColor($r('app.color.modalwindow_grey_3'))
                }
                .alignItems(HorizontalAlign.Start)
            }
            .alignItems(VerticalAlign.Center)
            .width($r('app.string.modalwindow_size_full'))

            Text(this.userName)
                .fontColor($r('app.color.modalwindow_grey_3'))
                .fontWeight(FontWeight.Bold)
                .padding({ left: $r('app.integer.modalwindow_padding_default') })
                .height($r('app.integer.modalwindow_user_image_height'))
                .width($r('app.string.modalwindow_size_full'))
                .borderRadius($r('app.integer.modalwindow_border_radius'))
                .backgroundColor($r('app.color.modalwindow_grey_e'))

            Text($r('app.string.modalwindow_verify_server_tip'))
                .fontColor($r('app.color.modalwindow_grey_6'))
                .width($r('app.string.modalwindow_size_full'))
                .textAlign(TextAlign.Start)

            Row() {
                Checkbox({ name: 'checkbox1' })
                    .id('default_agreement')
                    .select(this.isConfirmed)
                    .onChange((value: boolean) => {
                        this.isConfirmed = value
                    })
                ReadAgreement()
            }
            .width($r('app.string.modalwindow_size_full'))
            .alignItems(VerticalAlign.Center)

            Button($r('app.string.modalwindow_phone_start_login'))
                .fontColor(Color.White)
                .borderRadius($r('app.integer.modalwindow_border_radius'))
                .type(ButtonType.Normal)
                .backgroundColor($r('app.color.modalwindow_grey_2'))
                .onClick(() => {
                    if (this.isConfirmed) {
                        // 调用Toast显示登录成功提示
                        promptAction.showToast({ message: $r('app.string.modalwindow_login_success') });
                    } else {
                        // 调用Toast显示请先阅读并同意协议提示
                        promptAction.showToast({ message: $r('app.string.modalwindow_please_read_and_agree') });
                    }
                })
                .width($r('app.string.modalwindow_size_full'))
                .height($r('app.integer.modalwindow_height_fifty'))
            Row() {
                Text($r('app.string.modalwindow_other_way_login'))
                    .fontColor($r('app.color.modalwindow_grey_7'))
                    .backgroundColor($r('app.color.modalwindow_transparent_7'))
                    .onClick(() => {
                        this.isDefaultLogin = false;
                    })

                Blank() // 在容器主轴方向上自动填充容器空余部分

                Text($r('app.string.modalwindow_login_problems'))
                    .fontColor($r('app.color.modalwindow_grey_7'))
                    .backgroundColor($r('app.color.modalwindow_transparent_7'))
                    .onClick(() => {
                        // 调用Toast显示遇到问题提示
                        promptAction.showToast({ message: $r('app.string.modalwindow_login_problems') });
                    })
            }
            .width($r('app.string.modalwindow_size_full'))
        }
        .width($r('app.string.modalwindow_size_full'))
        .height($r('app.string.modalwindow_size_full'))
        .backgroundColor(Color.White)
        .justifyContent(FlexAlign.Center)
    }

    build() {
        Stack({ alignContent: Alignment.TopStart }) {
            // 登录方式有两种(默认一键登录方式和其他方式登录),需要在一个模态窗口中切换,使用if进行条件渲染
            if (this.isDefaultLogin) {
                this.DefaultLoginPage() // 默认一键登录方式
            } else {
                OtherWaysToLogin()// 其他登录方式
                    .transition(this.effect) // 此处涉及到组件的显示和消失,所以使用transition属性设置出现/消失转场
            }
            Image($r('app.media.arrow_back'))// 通过Stack组件,两个页面只实现一个back
                .id('login_back')
                .width($r('app.integer.modalwindow_height_twenty_five')).height($r('app.integer.modalwindow_height_twenty_five'))
                .margin({ top: $r('app.integer.modalwindow_margin_mid') })
                .onClick(() => {
                    if (this.isDefaultLogin) {
                        this.isPresentInLoginView = false;
                    } else {
                        this.isDefaultLogin = true
                    }
                })
        }
        .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.BOTTOM])
        .size({ width: $r('app.string.modalwindow_size_full'), height: $r('app.string.modalwindow_size_full') })
        .padding({
            top: $r('app.integer.modalwindow_padding_default'),
            left: $r('app.integer.modalwindow_padding_default'),
            right: $r('app.integer.modalwindow_padding_default')
        })
        .backgroundColor(Color.White) // 将模态页面背景设置为白色,以避免模态页面内组件发生显隐变化时露出下层页面
    }
}

3.2 状态变量解析

在 DefaultLogin 组件中,我们定义了以下状态变量:

@Link isPresentInLoginView: boolean;
@State isDefaultLogin: boolean = true;
userName: string = '18888888888';
isConfirmed: boolean = false;
private effect: TransitionEffect = TransitionEffect.OPACITY
    .animation({ duration: EFFECT_DURATION })
    .combine(TransitionEffect.opacity(EFFECT_OPACITY))
变量名装饰器类型作用
isPresentInLoginView@Linkboolean与父组件建立双向数据绑定,控制模态窗口的显示/隐藏
isDefaultLogin@Stateboolean控制当前显示的是默认登录页面还是其他登录方式页面
userNamestring存储用户手机号,此处为预设值
isConfirmedboolean记录用户是否同意服务协议
effectprivateTransitionEffect定义页面切换时的转场效果
3.2.1 @Link 装饰器

@Link装饰器用于在父子组件之间建立双向数据绑定。在我们的例子中,DefaultLogin 组件通过@Link 装饰的 isPresentInLoginView 变量与 ModalWindowComponent 中的 isPresent 变量建立了双向绑定。

当 DefaultLogin 组件中修改 isPresentInLoginView 的值时,ModalWindowComponent 中的 isPresent 也会同步更新,反之亦然。这种机制使得子组件可以控制父组件中的状态,实现更灵活的组件通信。

3.2.2 @State 装饰器

@State装饰器用于声明组件的内部状态。当@State 装饰的变量值发生变化时,框架会自动重新渲染组件。在 DefaultLogin 组件中,isDefaultLogin 变量控制显示默认登录页面还是其他登录方式页面。

3.2.3 TransitionEffect

TransitionEffect 用于定义组件的转场效果。在 DefaultLogin 组件中,我们定义了一个组合转场效果,包括透明度变化和动画持续时间:

private effect: TransitionEffect = TransitionEffect.OPACITY
    .animation({ duration: EFFECT_DURATION })
    .combine(TransitionEffect.opacity(EFFECT_OPACITY))

这个转场效果会在默认登录页面和其他登录方式页面之间切换时应用,提供平滑的视觉过渡。

4. UI 布局详解

4.1 整体布局

DefaultLogin 组件的 UI 布局采用嵌套的容器组件实现,主要包括:

  1. 最外层使用 Stack 组件,实现页面切换和返回按钮的叠加布局
  2. 内部使用 Column 组件作为主要容器,垂直排列各个 UI 元素
  3. 使用 Row 组件实现水平排列的元素,如用户头像和欢迎信息

4.2 用户信息区域

让我详细讲解这段用户信息区域的代码:

Row({ space: SPACE_TEN }) {  // 创建水平布局,设置子元素间距为10
    // 1. 用户头像
    Image($r('app.media.batman'))  // 加载本地图片资源
        .width($r('app.integer.modalwindow_user_image_height'))  // 设置图片宽度
        .height($r('app.integer.modalwindow_user_image_height')) // 设置图片高度

    // 2. 欢迎信息区域
    Column({ space: SPACE_TEN }) {  // 创建垂直布局,子元素间距为10
        // 2.1 欢迎回来文本
        Text($r('app.string.modalwindow_welcome_back'))
            .fontWeight(FontWeight.Bold)    // 设置字体粗细为粗体
            .fontSize($r('app.integer.modalwindow_font_size_mid'))  // 设置字体大小
            .fontColor(Color.Black)         // 设置字体颜色为黑色

        // 2.2 登录后更精彩提示文本
        Text($r('app.string.modalwindow_more_wonderful_after_login'))
            .fontColor($r('app.color.modalwindow_grey_3'))  // 设置字体颜色为灰色
    }
    .alignItems(HorizontalAlign.Start)  // 将Column内的文本左对齐
}
.alignItems(VerticalAlign.Center)  // Row内的元素垂直居中对齐
.width($r('app.string.modalwindow_size_full'))  // 设置整个Row的宽度为100%

代码结构分析:

  1. 外层容器

    • 使用 Row 组件创建水平布局
    • space: SPACE_TEN 设置子元素间距为 10 像素
    • .alignItems(VerticalAlign.Center) 使子元素垂直居中
    • .width($r('app.string.modalwindow_size_full')) 使容器宽度占满父容器
  2. 头像部分

    • 使用 Image 组件显示用户头像
    • 通过 $r('app.media.batman') 引用本地图片资源
    • 使用资源引用设置宽高,保证在不同设备上的一致性
  3. 文字信息部分

    • 使用 Column 组件创建垂直布局
    • 包含两个 Text 组件:
      • 欢迎语:粗体显示,黑色
      • 提示语:使用灰色显示
    • .alignItems(HorizontalAlign.Start) 确保文本左对齐

布局效果:

  • 左侧显示圆形头像
  • 右侧垂直排列两行文本
  • 整体垂直居中对齐
  • 文本左对齐排列
  • 组件间保持统一的间距

总结

本文详细介绍了 HarmonyOS NEXT 登录模块中 DefaultLogin 组件的实现,主要包括以下几个方面:

  1. 组件架构设计

    • 采用 ArkTS 声明式开发范式
    • 使用装饰器(@Link、@State)管理组件状态
    • 实现页面间平滑切换的转场效果
  2. UI 布局实现

    • 使用 Stack、Column、Row 等布局组件构建界面
    • 运用资源引用($r)确保界面在不同设备上的一致性
    • 实现了用户信息展示、协议确认、登录按钮等核心功能
  3. 交互功能

    • 实现一键登录和其他登录方式的切换
    • 添加服务协议确认机制
    • 集成返回按钮和页面导航功能
  4. 最佳实践

    • 组件状态管理的规范使用
    • UI 布局的模块化设计
    • 代码复用和维护性的考虑

通过本教程,开发者可以了解如何在 HarmonyOS NEXT 中实现一个功能完整、交互友好的登录页面,同时掌握 ArkTS 组件开发的核心概念和最佳实践。这些知识和技能可以应用到其他类似的组件开发中,帮助开发者构建更好的 HarmonyOS 应用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2314372.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

5.1 程序调试

版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的 本节中为了演示方便,使用的代码如下: 【例 5.1】【项目:code5-001】程序的调试。 static void Ma…

Cursor初体验:excel转成CANoe的vsysvar文件

今天公司大佬先锋们给培训了cursor的使用,还给注册了官方账号!跃跃欲试,但是测试任务好重,结合第三方工具开发也是没有头绪。 但巧的是,刚好下午有同事有个需求,想要把一个几千行的excel转成canoe的系统变…

vue3-element-admin 前后端本地启动联调

一、后端环境准备 1.1、下载地址 gitee 下载地址 1.2、环境要求 JDK 17 1.3、项目启动 克隆项目 git clone https://gitee.com/youlaiorg/youlai-boot.git数据库初始化 执行 youlai_boot.sql 脚本完成数据库创建、表结构和基础数据的初始化。 修改配置 application-dev.y…

《MySQL数据库从零搭建到高效管理|库的基本操作》

目录 一、数据库的操作 1.1 展示数据库 1.2 创建数据库 1.3 使用数据库 1.4 查看当前数据库 1.5 删除数据库 1.6 小结 二、常用数据类型 2.1 数值类型 2.2 字符串类型 2.3 日期类型 一、数据库的操作 打开MySQL命令行客户端,安装完MySQL后会有两个客户端…

mac使用Homebrew安装miniconda(mac搭建python环境),并在IDEA中集成miniconda环境

一、安装Homebrew mac安装brew 二、使用Homebrew安装miniconda brew search condabrew install miniconda安装完成后的截图: # 查看是否安装成功 brew list环境变量(无需手动配置) 先执行命令看能不能正常返回,如果不能正常…

Linux基础开发工具—vim

目录 1、vim的概念 2、vim的常见模式 2.1 演示切换vim模式 3、vim命令模式常用操作 3.1 移动光标 3.2 删除文字 3.3 复制 3.4 替换 4、vim底行模式常用命令 4.1 查找字符 5、vim的配置文件 1、vim的概念 Vim全称是Vi IMproved,即说明它是Vi编辑器的增强…

【C++】数据结构 队列的实现

本篇博客给大家带来的是用C语言来实现数据结构的队列的实现! 🐟🐟文章专栏:数据结构 🚀🚀若有问题评论区下讨论,我会及时回答 ❤❤欢迎大家点赞、收藏、分享! 今日思想:你…

macOS 终端优化

macOS 安装、优化、还原、升级 Oh My Zsh 完全指南 🚀 Oh My Zsh 是 macOS 终端增强的利器,它能提供强大的自动补全、主题定制和插件支持,让你的终端更高效、更炫酷。本文将全面介绍 如何安装、优化、还原、重新安装和升级 Oh My Zsh&#x…

大语言模型-1.2-大模型技术基础

简介 本博客内容是《大语言模型》一书的读书笔记,该书是中国人民大学高瓴人工智能学院赵鑫教授团队出品,覆盖大语言模型训练与使用的全流程,从预训练到微调与对齐,从使用技术到评测应用,帮助学员全面掌握大语言模型的…

Flutter 按钮组件 TextButton 详解

目录 1. 引言 2. TextButton 的基本用法 3. 主要属性 4. 自定义按钮样式 4.1 修改文本颜色 4.2 添加背景色 4.3 修改按钮形状和边距 4.4 样式定制 5. 高级应用技巧 5.1 图标文本组合 5.2 主题统一配置 5.3 动态交互 6. 性能优化与注意事项 6.1 点击区域优化 6.…

Qt 数据库操作(Sqlite)

数据库简介 关于数据库的基础知识这里就不做介绍了,相关博客可以查看: SQL基础知识 数据库学霸笔记 上面博客都写的比较详细,本文主要介绍如何使用Qt进行数据库相关操作,数据库分为关系型数据库和非关系型数据,关系…

vue 自行封装组件,类似于el-tree组件结构

背景: 接口返回是平面数组,需要经过分类处理,转成多维数组,以满足封装组件的数据结构。 有用到插件lodash。 import { groupBy, flattenDeep } from "lodash"; 效果展示: 处理数据: 对于接口返回…

信奥赛CSP-J复赛集训(模拟算法专题)(10):P2356 弹珠游戏

信奥赛CSP-J复赛集训(模拟算法专题)(10):P2356 弹珠游戏 题目背景 题目描述 MedalPluS 和他的小伙伴 NOIRP 发掘了一个骨灰级别的游戏——超级弹珠。 游戏的内容是:在一个 n n n \times n nn 的矩阵里,有若干个敌人,你的弹珠可以摧毁敌人,但只能攻击你所在的行、…

Windows 图形显示驱动开发-WDDM 3.2- WDDM 功能的内核模式测试

概述 在某些情况下,引入了基于 WDDM 或 MCDM 的新计算设备,并且这些设备的驱动程序不支持 D3D 运行时。 为了帮助验证此类驱动程序,将功能添加到 Dxgkrnl ,以便仅使用内核模式 thunk 进行验证;也就是说,无需涉及 D3D …

SpringBoot 入门--工程创建

IDEA创建SpringBoot项目 SpringBoot 3.1.5 需要java17 ① 创建Maven工程 ② 导入spring-boot-stater-web起步依赖 ③ 编写Controller ④ 提供启动类 1.打开IDEA,新建项目 2.点击下一步,并勾选web开发相关依赖 3.勾选完点击Create,然后配置…

Rust 之一 基本环境搭建、各组件工具的文档、源码、配置

概述 Rust 是一种强调性能、类型安全和并发性的通用编程语言。它强制执行内存安全,使用其特有的所有权机制,而无需传统的垃圾收集器。Rust 不强制执行编程范式,但受到函数式编程思想的影响。 最初是由 Mozilla 员工 Graydon Hoare 在 2006 年…

《基于机器学习的DDoS攻击检测与防御系统设计与实现》开题报告

目录 一、课题的研究目的和意义 1.1课题背景 1.2课题目的 (1)提高DDoS攻击检测的准确性 (2)加强DDoS攻击的防御能力 (3)提升网络安全防护的技术水平 1.3课题意义 (1)理论意义…

【2025】基于springboot+vue的汽车销售试驾平台(源码、万字文档、图文修改、调试答疑)

基于 Spring Boot Vue 的汽车销售试驾平台通过整合前后端技术,实现了汽车销售和试驾预约的信息化和智能化。系统为管理员和用户提供了丰富的功能,提升了客户体验和销售效率,增强了数据分析能力,为汽车销售行业的发展提供了新的途…

C语言每日一练——day_5

引言 针对初学者,每日练习几个题,快速上手C语言。第五天。(连续更新中) 采用在线OJ的形式 什么是在线OJ? 在线判题系统(英语:Online Judge,缩写OJ)是一种在编程竞赛中用…

【社区投稿】深入再谈智能指针、AsRef引用与Borrow借用

深入再谈智能指针、AsRef引用与Borrow借用 这是一个具有深度的技术主题。每次重温其理论知识&#xff0c;都会有新的领悟。大约 2 年前&#xff0c;我曾就这一技术方向撰写过另一篇短文《从类型转换视角&#xff0c;浅谈Deref<Target T>, AsRef<T>, Borrow<T&g…