#鸿蒙开发#ArkUI与Axios构建安全高效的登录注册流程
引言 在现代的移动应用中,登录和注册必不可少,而鸿蒙又是现在的发展趋势,然而在网上却很难找到,一个完整的ArkUI实现的登录注册案例,并且是实现了功能的。本文将介绍一个使用ArkUI框架实现的简单而高效的登录和注册界面案例,并详细解析其代码绘制界面的过程以及功能实现的细节,通过过这个案例,
引言
在现代的移动应用中,登录和注册必不可少,而鸿蒙又是现在的发展趋势,然而在网上却很难找到,一个完整的ArkUI实现的登录注册案例,并且是实现了功能的。本文将介绍一个使用ArkUI框架实现的简单而高效的登录和注册界面案例,并详细解析其代码绘制界面的过程以及功能实现的细节,通过过这个案例,读者可以了解到如何在ArkUI中使用HTTP请求和Axios库与后端服务器进行交互,以及如何管理组件状态以实现动态界面更新。该案例不仅实现了基本的登录和注册功能,还解决了验证码倒计时、动态错误提示等常见痛点。
目标读者
本文适合所有对ArkUI框架感兴趣,希望了解如何实现登录和注册功能的开发者。无论你是初学者还是有经验的开发者,都可以通过本文获得对ArkUI框架的更深入理解,并学习如何处理HTTP请求和状态管理。
文章结构
文章将按照以下结构进行:
- 技术栈介绍:简述ArkUI、HTTP请求和Axios库的基本概念和技术优势。
- 代码结构与界面设计:详细说明代码的整体结构和每个部分的界面设计思路。
- 功能实现:深入解析发送验证码和登录/注册功能的具体实现细节。
- Axios与请求拦截器:了解到如何在项目中进行基础的HTTP请求配置,并确保在用户未登录的情况下,阻止对需要认证的API的访问,并引导用户到登录注册页面。
在接下来的内容中,我们将逐一探讨这些部分,帮助你更好地理解和实现这个登录和注册案例。现在,让我们从技术栈介绍开始吧。

技术栈介绍
ArkUI
ArkUI 是一个由华为开发的高性能、高可靠性的跨平台UI开发框架,专为全场景生态设计。它旨在提供统一的开发体验,支持多种设备,包括智能手机、平板、智能穿戴设备等。ArkUI采用声明式编程模型,使得开发者可以通过简洁的代码来描述UI界面,从而提高开发效率和代码可维护性。
主要特点
- 声明式编程模型:通过描述UI的状态和行为来实现界面更新,简化代码逻辑。
- 高性能:优化的渲染引擎和高效的组件复用机制,确保应用的流畅运行。
- 跨平台支持:支持多种设备和操作系统,减少重复开发工作。
- 丰富的组件库:提供大量的内置组件,满足各种复杂的UI需求。
HTTP请求
HTTP请求 是一种通过网络协议(如HTTP或HTTPS)与服务器进行通信的方式。在移动应用开发中,HTTP请求常用于获取和发送数据,实现用户登录、注册等功能。ArkUI框架提供了@ohos.net.http模块来处理HTTP请求。
主要特点
- 简单易用:提供简洁的API接口,方便开发者进行HTTP请求。
- 支持多种方法:包括GET、POST、PUT、DELETE等HTTP方法。
- 支持自定义请求头和数据:可以灵活地设置请求头和请求数据,满足不同的业务需求。
- 错误处理:提供详细的错误信息,帮助开发者调试和处理请求失败的情况。
Axios
Axios 是一个基于Promise的HTTP客户端,可以用于浏览器和Node.js中。它在移动端应用开发中常用于与后端服务器进行数据交互。Axios提供了丰富的功能和灵活的配置选项,使得HTTP请求更加简单和高效。
主要特点
- 基于Promise:支持异步操作,便于处理请求的成功和失败情况。
- 拦截器:可以拦截请求和响应,方便进行预处理和后处理。
- 转换请求和响应数据:支持对请求和响应数据进行自动转换,简化数据处理过程。
- 取消请求:允许取消正在进行的请求,避免无用的数据传输。
- 自动转换JSON数据:默认情况下,自动将请求和响应的数据格式化为JSON,方便使用。
好了,由于笔者了解也有限,可能也并不太深入,大家有兴趣的可以自行去学习,技术就介绍到这里。
接下来,我们将详细解析代码的整体结构和界面设计思路。
代码结构与界面设计
在本部分中,我们将详细说明代码的整体结构和每个部分的界面设计思路。通过这些说明,你可以更好地理解如何在ArkUI中构建复杂的UI界面,并实现与后端服务器的交互。
整体结构
首先,我们来看一下整个代码的结构:
@Entry
@Component
struct LoginRegister {
@State phone: string = ''
@State code: string = ''
@State errorMessage: string = ''
@State isAgree: boolean = false
@State countdown: number = 60
@State isCounting: boolean = false
@State loginData: LoginData | null = null;
private interval: number | null = null; // 存储 interval 的引用
// 发送验证码的API调用
sendVerificationCode(phone: string) { ... }
// 登录或注册的API调用
loginOrRegister(phone: string, code: string) { ... }
startCountdown() : void { ... }
build() { ... }
@Builder
logoComponent() { ... }
}
主要部分
-
方法定义:定义了几个关键方法,包括发送验证码、登录或注册以及启动倒计时。
-
界面构建:通过build方法构建整个登录和注册界面。
-
自定义组件:使用@Builder装饰器定义了一个可复用的logoComponent。
界面设计
我们挑一些主要的实现,来给大家介绍一下:
手机或验证码的输入框
Row() { IconColumnView({imagePath: "app.media.ic_phone"}) Column() { TextInput({ placeholder: '请输入手机号', text: this.phone, }) .placeholderColor('rgba(0, 0, 0, 0.6)') .fontColor(Color.Black) .width('100%') .borderRadius(15) .backgroundColor('#EDEDED') .caretColor('#000000') .height(39) .onChange((value: string) => { this.phone = value; if (this.phone === '' || this.phone.length !== 11 || !/^\d+$/.test(this.phone)) { // 检查手机号是否为空,或者长度是否不等于11位,并且是否只包含数字 if (this.phone === '') { this.errorMessage = ''; // 如果输入为空,清空错误信息 } else { this.errorMessage = '请输入有效的手机号'; // 如果输入不符合条件,设置错误信息 } } else { this.errorMessage = ''; // 如果符合条件,清空错误信息 } }) } .width('85.8%') .backgroundColor('#EDEDED') .borderRadius({ topLeft: 0, topRight: 15, bottomLeft: 0, bottomRight: 15 }) } .width('91%') .borderRadius(15) .backgroundColor('#EDEDED') .margin({ top: 45 })感觉笔者实现的可能有点复杂了,需求要在输入框的前面显示一个图标,用来表示这是手机或验证码的输入框,而我的实现方式是将两列叠在一起,有什么组件或者好的实现方式可以告诉我。

这里也没什么可讲的,在实现功能时我们还是要使用onChange事件:当用户输入手机号时,检查输入格式是否正确。如果不正确,则显示错误信息。
下面就是手机号和验证码的实现完成的图示

登录按钮
登录按钮允许用户使用手机号和验证码进行登录或注册。
Row() { Button('登录', { type: ButtonType.Normal }) .width('67.7%') .height(39) .backgroundColor($r('sys.color.black')) .fontColor('#BEFF33') .fontSize(20) .borderRadius(15) .onClick(() => { if (this.phone.length === 11 && this.code.length > 0) { this.loginOrRegister(this.phone, this.code); } }) } .margin({ top: 28 }) .justifyContent(FlexAlign.Center) .width('100%')主要也没什么可讲的主要就是调整样式和onClick事件,当用户点击按钮时,检查手机号和验证码是否正确。如果正确,则调用loginOrRegister方法。

错误提示信息
一个完整的登录注册不能只有输入框,登录按钮就行了,还需要错误提示信息用于显示用户输入错误或请求失败的信息。
Row() { if (this.errorMessage === '') { Text('') } else { Text(this.errorMessage) .fontSize(14) .fontColor('#F50000') } } .width('91%')当然这些错误提示信息需要你在其他的代码逻辑中给出,实现。后面我的介绍中也会提到。
协议和隐私政策
一个好的应用,这一点是必不可少的,我在这部分将这些封装到一个小view中以方便后面其他界面的复用,嗯感觉也有点复杂,怕登录页面代码太多就把这些放在view中了,有没有只用一个Text就可以放完这些文字的组件。求指导。

import { router } from '@kit.ArkUI' @Component export struct agreementView { @Link isAgree: boolean build() { Row() { Checkbox() .width(17) .height(15) .shape(CheckBoxShape.ROUNDED_SQUARE) .select(this.isAgree) .mark({ strokeColor: '#BEFF33' }) .selectedColor($r('sys.color.black')) .borderRadius(6) .onClick(() => { this.isAgree = !this.isAgree }) Text('我已阅读并同意') .fontColor($r('app.color.menu_font_color')) .fontSize(14) .lineHeight(20.27) Text('用户协议') .fontSize(14) .lineHeight(20.27) .onClick(() => { router.pushUrl({ url: 'pages/UserAgreementPage' // 目标页面的 URL }); }) Text('和') .fontSize(14) .lineHeight(20.27) .fontColor($r('app.color.menu_font_color')) Text('隐私政策') .fontSize(14) .lineHeight(20.27) .onClick(() => { router.pushUrl({ url: 'pages/PrivacyPolicyPage' // 目标页面的 URL }); }) } .width('100%') .height(21) .alignItems(VerticalAlign.Center) .justifyContent(FlexAlign.Center) .margin({ top: 26 }) } }使用
//协议和隐私政策 agreementView({isAgree :this.isAgree})样式调整
为了让整个登录注册更美观一点,当然这是我们产品的功劳。下面给出我案例的登录注册部分。我讲一下这个底层绿色的怎么实现,界面设计就讲到这,其他都是一些简单的布局和组件的使用。

代码实现//底层遮罩层(绿色) Column() { } .width('74.4%') .height(276) .backgroundColor('rgba(173, 212, 91, 0.8)') .borderRadius(6) .position({ x: 66, y: 28 }) .zIndex(0)我采用了绝对定位+zindex设置层级的方式实现的,当然也可以使用,stack层叠布局来实现。Position类型基于父组件左上角确定位置,zindex(0)设置层级最低。即可实现。我感觉加了一个这个真的挺好看的,产品的眼光真好。
通过以上对代码结构和界面设计的详细说明,你可以了解到如何在ArkUI中构建简单的登录注册UI界面,接下来,我们将深入解析发送验证码和登录/注册功能的具体实现细节。
功能实现
接下来就进入主要的部分,功能实现环节,可能在本部分中,我们将深入解析发送验证码和登录/注册功能的具体实现细节。通过这些解析,你可以了解到如何在ArkUI中使用HTTP请求和Axios库与后端服务器进行交互,并如何管理组件状态以实现动态界面更新。
发送验证码功能
发送验证码功能通过sendVerificationCode方法实现。该方法首先检查用户是否同意了协议和隐私政策,然后通过HTTP请求发送验证码到指定手机号。
//发送验证码的api调用
sendVerificationCode(phone: string) {
if (this.isAgree === false) {
this.errorMessage = '请先同意协议和隐私政策';
return;
} else {
this.errorMessage = '';
}
let httpRequest = http.createHttp();
httpRequest.request(
'你的api地址',
{
method: http.RequestMethod.POST,
header: { 'Content-Type': 'application/json' },
extraData: {
phone: phone,
}
}, (err, data) => {
if (!err) {
console.log('验证码发送成功');
this.startCountdown();
} else {
console.error('验证码发送失败', err);
this.errorMessage = '验证码发送失败,请重试';
}
});
}
详细步骤
- 检查协议同意状态
使用this.isAgree检查用户是否同意了协议和隐私政策。并更新错误信息 - 创建创建HTTP请求:
使用http.createHttp()创建一个HTTP请求实例。 - 发送POST请求
使用httpRequest.request方法发送POST请求到指定的URL,设置请求头为{'Content-Type': 'application/json'},设置请求数据为{ phone: phone }。 - 处理响应
如果请求成功 (!err),则在控制台输出“验证码发送成功”,并调用this.startCountdown()启动倒计时,如果请求失败 (err),则在控制台输出错误信息,并设置this.errorMessage为“验证码发送失败,请重试”。登录注册功能
登录或注册功能通过loginOrRegister方法实现。该方法使用Axios库发送POST请求到指定的URL,并处理请求的成功和失败情况。
```javascript
//登录注册的api调用
loginOrRegister(phone: string, code: string) {
console.log('尝试登录或注册的手机号和验证码:', phone, code); // 添加测试日志
axios.post('你的api地址', {
phone: phone,
code: code,
})
.then((response: AxiosResponse) => {
console.log('响应数据:', response.data); // 添加测试日志
const parsedData: LoginData = response.data; // 使用 LoginData 接口明确类型
console.log('解析后的数据:', parsedData); // 添加测试日志
if (parsedData && parsedData.flag) {
console.log('登录或注册成功,设置登录数据并跳转'); // 添加测试日志
this.loginData = parsedData;
dataPreferences?.putSync("token", parsedData.data);
dataPreferences?.flush();
console.log('准备跳转到 /pages/Tabs'); // 添加测试日志
router.pushUrl({
url: 'pages/Tabs' // 目标页面的 URI
});
console.log('跳转完成后'); // 添加测试日志
} else {
console.error('登录或注册失败', parsedData.msg); // 添加测试日志
if (parsedData.msg && parsedData.msg.includes('验证码错误')) {
this.errorMessage = '验证码错误,请重试';
} else {
this.errorMessage = '登录或注册失败,请重试';
}
}
})
.catch((error: AxiosError) => { // 使用 AxiosError 明确类型
console.error('登录或注册失败', error); // 添加测试日志
console.error('错误信息:', error.message); // 添加测试日志
console.error('错误响应:', error.response); // 添加测试日志
console.error('错误配置:', error.config); // 添加测试日志
console.error('错误状态码:', error.response?.status); // 添加测试日志
console.error('错误状态文本:', error.response?.statusText); // 添加测试日志
this.errorMessage = 登录或注册失败,请重试: ${error.message};
});
}
**详细步骤**
1. 发送POST请求
使用axios.post方法发送POST请求到指定的URL,设置请求数据为{ phone: phone, code: code }。
2. 处理成功响应
在then回调中,使用console.log输出响应数据。解析响应数据为LoginData类型。如果parsedData.flag为true,表示登录或注册成功。设置this.loginData为解析后的数据。使用dataPreferences.putSync保存token,并调用dataPreferences.flush刷新数据。使用router.pushUrl跳转到目标页面 (/pages/Tabs)。
如果parsedData.flag为false,表示登录或注册失败。使用console.error输出错误信息。
根据错误信息的具体内容,设置this.errorMessage为相应的提示信息。
3. 处理失败响应
在catch回调中,使用console.error输出详细的错误信息,包括错误信息、响应数据、配置信息、状态码和状态文本。设置this.errorMessage为“登录或注册失败,请重试”,并附带具体的错误信息。
### 倒计时功能
倒计时功能通过startCountdown方法实现。该方法启动一个定时器,每秒更新一次验证码按钮的倒计时状态。
```javascript
startCountdown() : void {
if (this.isCounting) return; // 如果已经在倒计时,则不重复启动
this.isCounting = true; // 开始计时
this.countdown = 60; // 初始化倒计时为60秒
// 每秒更新一次倒计时
this.interval = setInterval(() => {
if (this.countdown > 0) {
this.countdown--;
} else {
clearInterval(this.interval!);
this.isCounting = false; // 结束倒计时
this.interval = null; // 重置 interval 引用
}
}, 1000);
}
显示倒计时
在界面点击发送显示倒计时
Column() {
// 发送验证码按钮
Text(this.isCounting ? `(${this.countdown})` : '发送')
.textAlign(TextAlign.Center)
.width('100%')
.height(39)
.fontColor('#000000')
.fontSize(16)
.borderRadius(6)
.backgroundColor('#CCCCCC')//倒计时显示
.enabled(!this.isCounting && this.phone.length === 11 && /^[0-9]+$/.test(this.phone))
.onClick(() => {
this.sendVerificationCode(this.phone);
})
}
.margin({ left: 5 })
详细步骤
- 检查是否已经在倒计时
如果this.isCounting为true,则直接返回,避免重复启动倒计时。 - 初始化倒计时状态
- 启动定时器
使用setInterval每秒执行一次回调函数。在回调函数中,检查this.countdown是否大于0。如果是,则每秒递减1。如果this.countdown等于0,则清除定时器 (clearInterval(this.interval!)),设置this.isCounting为false,并重置this.interval为null。
通过以上解析,你已经了解到如何在ArkUI中实现发送验证码、倒计时和登录/注册功能。接下来,我来介绍一下Axios配置与拦截器,以便更加完善这个登录注册功能
Axios配置与拦截器
在本部分中,我们将介绍与登录注册相关的Axios配置,特别是请求拦截器的实现。这部分内容将帮助你理解如何确保在用户未登录的情况下,阻止对需要认证的API的访问,并引导用户到登录注册页面。
Axios配置
首先,我们来看一下Axios的配置部分
import { AxiosError, AxiosResponse, InternalAxiosRequestConfig } from '@ohos/axios';
import { dataPreferences } from '../../entryability/EntryAbility';
import axios from '../AxiosRequest';
import { router } from '@kit.ArkUI';
axios.defaults.baseURL = "http://xxx/xxx";
const instance = axios.create({
headers: { 'Content-Type': 'application/json' },
});
const noTokenRequiredUrls = [
'http://xxx/login/phone',
'http://xxx/login/sendMsg',
'/xxx'
];
const noNeedRouter = [
'/xxx'
];
详细说明
- 基础URL (baseURL):设置所有请求的基础URL为http://xxx/xxx%EF%BC%8C%E7%AE%80%E5%8C%96%E8%AF%B7%E6%B1%82%E8%B7%AF%E5%BE%84%E3%80%82
- 实例创建 (instance):使用axios.create创建一个Axios实例,并设置默认请求头为{'Content-Type': 'application/json'}。
- 无需Token的URL列表 (noTokenRequiredUrls):定义一个数组,包含不需要token的URL,如登录和发送验证码的接口。
- 无需路由的URL列表 (noNeedRouter):定义一个数组,包含不需要重定向到登录页面的URL,如获取xxx数据的接口。
请求拦截器
请求拦截器用于在发送请求之前检查用户是否已经登录,并根据需要添加token或重定向到登录页面。详细步骤// 添加请求拦截器 instance.interceptors.request.use(async (config: InternalAxiosRequestConfig) => { const isNoTokenRequired = noTokenRequiredUrls.some(url => config.url?.includes(url)); let token: string = ""; if (!isNoTokenRequired) { token = await dataPreferences?.get("token", "") as string; if (!token || token == "" || token == "null" || token == "undefined") { if (!noNeedRouter.some(url => config.url?.includes(url))) { router.pushUrl({ url: "pages/LoginRegister" }); } return Promise.reject('用户未登录'); } config.headers["token"] = token; } return config; }, (error: AxiosError) => { // 对请求错误做些什么 return Promise.reject(error); });
- 检查是否需要Token:
- 使用noTokenRequiredUrls数组检查当前请求的URL是否在无需token的URL列表中。
- 如果请求的URL在列表中,则isNoTokenRequired为true,跳过token检查。
- 获取Token:
如果请求需要token,则从dataPreferences中获取token。 - 验证Token:
- 检查获取到的token是否为空、null或undefined。
- 如果token无效,则根据请求URL是否在noNeedRouter列表中决定是否重定向到登录页面。
如果请求URL不在noNeedRouter列表中,则使用router.pushUrl重定向到pages/LoginRegister。
返回一个被拒绝的Promise,表示用户未登录。
- 添加Token到请求头:
如果token有效,则将其添加到请求头中 (config.headers["token"] = token)。 - 返回配置:
返回修改后的请求配置 (config)。 - 处理请求错误:
如果请求配置过程中发生错误,则返回一个被拒绝的Promise,包含具体的错误信息。
为了更好地理解这些配置如何应用于具体的功能,我们来看一个与登录注册相关的接口示例
export async function planJourney(routeId: number, day: number) {
const params = JSON.stringify({
routeId: routeId,
day: day
});
return (await instance.post(`/planJourney`, params)).data;
}
- 请求路径:/planJourney是需要认证的API路径。
- 请求方法:使用instance.post方法发送POST请求。
- 请求数据:将routeId和day参数序列化为JSON字符串并作为请求数据发送。
- 拦截器应用:
在请求拦截器中,检查/planJourney是否在noTokenRequiredUrls列表中。
由于/planJourney不在列表中,拦截器将获取token并添加到请求头中。
如果token无效,则重定向到登录页面 (pages/LoginRegister)。
通过以上对Axios配置和拦截器的详细说明,你可以了解到如何在项目中进行基础的HTTP请求配置,并确保在用户未登录的情况下,阻止对需要认证的API的访问,并引导用户到登录注册页面。
总结
通过本文的详细介绍,我们深入探讨了如何在ArkUI框架中实现一个完整的登录和注册功能,并结合Axios库进行HTTP请求的处理。我们从技术栈的选择开始,逐步解析了代码的整体结构和界面设计,详细说明了发送验证码、登录/注册以及倒计时功能的实现细节。此外,我们还介绍了如何配置Axios拦截器,确保在用户未登录的情况下,阻止对需要认证的API的访问,并引导用户到登录注册页面。希望这个案例可以帮到大家。
openHarmony官方文档
HarmonyOS官方文档
axios官方文档
希望这些资源能够帮助你进一步学习和掌握ArkUI和Axios的相关知识。

更多推荐

所有评论(0)