
1. 页面路由概述
在HarmonyOS应用开发中,页面路由和导航是实现多页面应用的核心机制。良好的路由管理可以提供流畅的用户体验,简化页面间的数据传递和状态管理。ArkTS提供了多种路由实现方式,包括原生路由能力和第三方路由框架。
1.1 路由的基本概念
- 页面路由:指应用中不同页面之间的切换和跳转机制
- 导航栈:管理页面层级关系的后进先出(LIFO)数据结构
- 页面参数传递:在页面跳转过程中携带和接收数据的方式
- 路由拦截:在页面跳转前后执行自定义逻辑的能力
11.2 ArkTS中的路由方案对比
| 路由方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 原生路由Router | 系统内置,轻量简单 | 功能相对基础,缺乏高级特性 | 简单的页面跳转场景 |
| Navigator组件 | 声明式导航,与UI结合紧密 | 灵活性受限,不支持复杂的路由管理 | 简单的页面间导航 |
| HMRouter框架 | 功能丰富,支持声明式配置,动画效果好 | 需要额外安装依赖 | 复杂应用、需要高级路由特性的场景 |
2. 原生路由Router的使用
HarmonyOS提供了内置的@ohos.router模块,用于实现基本的页面跳转和导航功能。
2.1 Router模块的基本用法
首先,需要导入Router模块:
import router from '@ohos.router';
页面跳转(push操作)
// 不带参数的页面跳转
router.push({
url: 'pages/DetailPage'
});
// 带参数的页面跳转
router.push({
url: 'pages/DetailPage',
params: {
itemId: '123',
itemName: '示例商品'
}
});
返回上一页(back操作)
// 返回上一页
router.back();
// 带返回参数的返回
router.back({
params: {
result: 'success',
data: {}
}
});
替换当前页(replace操作)
// 替换当前页面,用户无法返回到被替换的页面
router.replace({
url: 'pages/LoginPage'
});
2.2 页面参数的接收和处理
在目标页面中,可以通过router.getParams()方法获取从上一个页面传递过来的参数:
// 在目标页面中获取参数
import router from '@ohos.router';
@Entry
@Component
export struct DetailPage {
private itemId: string = '';
private itemName: string = '';
onPageShow() {
// 获取路由参数
const params = router.getParams();
if (params) {
this.itemId = params.itemId as string;
this.itemName = params.itemName as string;
}
}
build() {
Column() {
Text(`商品ID: ${this.itemId}`)
Text(`商品名称: ${this.itemName}`)
}
}
}
2.3 页面生命周期与路由事件
在使用路由时,需要了解页面的生命周期事件:
@Entry
@Component
export struct MyPage {
// 页面创建时调用
onCreate() {
console.info('页面创建');
}
// 页面显示时调用
onPageShow() {
console.info('页面显示');
// 可以在这里获取路由参数或刷新数据
}
// 页面隐藏时调用
onPageHide() {
console.info('页面隐藏');
}
// 页面销毁时调用
onDestroy() {
console.info('页面销毁');
// 在这里释放资源
}
build() {
// UI组件定义
}
}
3. HMRouter路由框架详解
HMRouter是HarmonyOS生态中功能丰富的第三方路由框架,提供了声明式配置、强大的动画效果和灵活的导航管理能力。
3.1 HMRouter的安装与配置
首先,通过OHPM安装HMRouter框架:
ohpm install @hadss/hmrouter @hadss/hmrouter-transitions
安装完成后,在项目的oh-package.json5中会自动添加依赖:
{
"dependencies": {
"@hadss/hmrouter": "^1.2.0-rc.0",
"@hadss/hmrouter-transitions": "^1.2.0-rc.0"
}
}
3.2 HMRouter的初始化
在应用的入口Ability中初始化HMRouter:
// EntryAbility.ets
import { HMRouterMgr } from '@hadss/hmrouter';
import UIAbility from '@ohos.app.ability.UIAbility';
import window from '@ohos.window';
export default class EntryAbility extends UIAbility {
onCreate(want, launchParam) {
// 初始化HMRouter
HMRouterMgr.init({
context: this.context,
});
console.log('EntryAbility onCreate');
}
onWindowStageCreate(windowStage: window.WindowStage) {
// 设置WindowStage
windowStage.loadContent('pages/Index', (err, data) => {
if (err.code) {
console.error('Failed to load the content. Cause: ' + JSON.stringify(err));
return;
}
console.log('Succeeded in loading the content. Data: ' + JSON.stringify(data));
});
}
}
3.3 页面注册与配置
使用@HMRouter装饰器注册页面:
// 页面路径常量管理
// constants/PagePath.ets
export class PagePath {
static readonly INDEX: string = 'pages/Index';
static readonly DETAIL: string = 'pages/DetailPage';
static readonly SETTINGS: string = 'pages/SettingsPage';
}
// 在页面组件中注册
// pages/DetailPage.ets
import { HMRouter } from '@hadss/hmrouter';
import { PagePath } from '../constants/PagePath';
@HMRouter({ pageUrl: PagePath.DETAIL })
@Entry
@Component
export struct DetailPage {
// 页面内容
build() {
Column() {
Text('详情页面')
}
}
}
3.4 使用HMRouter进行页面导航
基本页面跳转
import { HMRouterMgr } from '@hadss/hmrouter';
import { PagePath } from '../constants/PagePath';
// 页面跳转
HMRouterMgr.push({
pageUrl: PagePath.DETAIL,
param: {
productId: '1001',
productName: '测试产品'
}
});
参数接收
在目标页面中,可以直接通过装饰器接收路由参数:
import { HMRouter, Param } from '@hadss/hmrouter';
import { PagePath } from '../constants/PagePath';
@HMRouter({ pageUrl: PagePath.DETAIL })
@Entry
@Component
export struct DetailPage {
@Param productId?: string;
@Param productName?: string;
build() {
Column() {
Text(`产品ID: ${this.productId}`)
Text(`产品名称: ${this.productName}`)
}
}
}
返回上一页
// 简单返回
HMRouterMgr.pop();
// 带返回参数的返回
HMRouterMgr.pop({
param: {
result: 'success',
selectedItem: { id: '1', name: '选项1' }
}
});
替换页面
HMRouterMgr.replace({
pageUrl: PagePath.SETTINGS
});
清空导航栈并跳转
HMRouterMgr.replaceAll({
pageUrl: PagePath.LOGIN
});
3.5 HMNavigation导航容器
HMRouter提供了HMNavigation组件,用于实现更高级的导航功能:
import { HMNavigation, HMDefaultGlobalAnimator } from '@hadss/hmrouter';
@Entry
@Component
export struct AppRouter {
build() {
HMNavigation({
navigationId: 'MainNavigation',
homePageUrl: 'pages/Index',
options: {
standardAnimator: HMDefaultGlobalAnimator.STANDARD_ANIMATOR,
dialogAnimator: HMDefaultGlobalAnimator.DIALOG_ANIMATOR
}
})
}
}
4. ArkTS中的状态管理与页面间数据传递
4.1 状态管理装饰器
在ArkTS中,有多种状态管理装饰器可用于页面间的数据传递和状态管理:
- @State:组件内的状态变量,变化时会触发UI刷新
- @Prop:父组件向子组件传递数据的单向绑定
- @Link:父子组件间的双向绑定
- @Provide/@Consume:跨层级组件间的状态传递
- @LocalStorage:本地存储状态,应用级别持久化
- @AppStorage:应用级全局状态管理
4.2 页面间数据传递方式
通过路由参数传递
// 发送页面
HMRouterMgr.push({
pageUrl: PagePath.DETAIL,
param: {
userId: '12345',
userName: '张三'
}
});
// 接收页面
@HMRouter({ pageUrl: PagePath.DETAIL })
@Entry
@Component
export struct DetailPage {
@Param userId?: string;
@Param userName?: string;
build() {
Column() {
Text(`用户ID: ${this.userId}`)
Text(`用户名: ${this.userName}`)
}
}
}
通过全局状态传递
// 发送页面
@Entry
@Component
export struct SenderPage {
onSendData() {
// 使用AppStorage传递数据
AppStorage.SetOrCreate('sharedData', {
message: 'Hello from sender page',
timestamp: Date.now()
});
// 跳转到接收页面
HMRouterMgr.push({ pageUrl: PagePath.RECEIVER });
}
}
// 接收页面
@HMRouter({ pageUrl: PagePath.RECEIVER })
@Entry
@Component
export struct ReceiverPage {
@StorageLink('sharedData') sharedData: any = null;
build() {
Column() {
if (this.sharedData) {
Text(`接收到的数据: ${this.sharedData.message}`)
Text(`时间戳: ${this.sharedData.timestamp}`)
} else {
Text('暂无数据')
}
}
}
}
通过全局对象传递
// 在全局作用域定义数据
globalThis.familyTree = new FamilyTree();
// 在任意页面中访问和修改
@HMRouter({ pageUrl: PagePath.FAMILY_TREE })
@ComponentV2
export struct FamilyTreeView {
@Local familyTree: FamilyTree = globalThis.familyTree || new FamilyTree()
build() {
// 使用familyTree数据
}
}
5. 导航动画效果
5.1 HMRouter的内置动画
HMRouter提供了多种内置的过渡动画效果:
import { HMNavigation, HMDefaultGlobalAnimator } from '@hadss/hmrouter';
import { TransitionAnimatorType } from '@hadss/hmrouter/transition';
@Entry
@Component
export struct AppRouter {
build() {
HMNavigation({
navigationId: 'MainNavigation',
homePageUrl: 'pages/Index',
options: {
standardAnimator: HMDefaultGlobalAnimator.get(TransitionAnimatorType.FADE),
dialogAnimator: HMDefaultGlobalAnimator.get(TransitionAnimatorType.SLIDE)
}
})
}
}
5.2 自定义导航动画
可以通过HMRouter的动画配置实现自定义导航效果:
import { HMNavigation } from '@hadss/hmrouter';
import { TransitionAnimator } from '@hadss/hmrouter/transition';
@Entry
@Component
export struct AppRouter {
// 自定义动画配置
private customAnimator = new TransitionAnimator({
push: {
duration: 500,
curve: 'ease',
delay: 0,
styles: {
enter: {
opacity: [0, 1],
transform: [
{ translateX: ['100%', '0%'] }
]
},
exit: {
opacity: [1, 0.8],
transform: [
{ translateX: ['0%', '-30%'] }
]
}
}
},
pop: {
duration: 500,
curve: 'ease',
delay: 0,
styles: {
enter: {
opacity: [0.8, 1],
transform: [
{ translateX: ['-30%', '0%'] }
]
},
exit: {
opacity: [1, 0],
transform: [
{ translateX: ['0%', '100%'] }
]
}
}
}
});
build() {
HMNavigation({
navigationId: 'MainNavigation',
homePageUrl: 'pages/Index',
options: {
standardAnimator: this.customAnimator
}
})
}
}
6. 路由守卫与拦截
6.1 全局路由守卫
HMRouter支持全局路由守卫,可以在所有页面跳转前后执行自定义逻辑:
// EntryAbility.ets 中配置
import { HMRouterMgr, RouterGuard } from '@hadss/hmrouter';
onCreate(want, launchParam) {
// 初始化HMRouter
HMRouterMgr.init({
context: this.context,
// 全局路由守卫
beforeEach: (to, from, next) => {
console.log(`即将从${from.pageUrl}跳转到${to.pageUrl}`);
// 检查用户是否登录
const isLoggedIn = this.checkUserLogin();
const needAuth = ['pages/ProfilePage', 'pages/SettingsPage'];
if (needAuth.includes(to.pageUrl) && !isLoggedIn) {
// 需要登录但用户未登录,跳转到登录页
next({
replace: true,
pageUrl: 'pages/LoginPage',
param: { redirectUrl: to.pageUrl }
});
} else {
// 允许跳转
next();
}
},
afterEach: (to, from) => {
console.log(`已从${from?.pageUrl}跳转到${to.pageUrl}`);
// 可以在这里添加页面访问统计等逻辑
}
});
}
7. 实际应用案例
7.1 猜数字游戏的路由扩展
基于现有的猜数字游戏,我们可以扩展为多页面应用,演示路由功能:
1. 创建游戏设置页面
// pages/GameSettings.ets
import { HMRouter } from '@hadss/hmrouter';
import { PagePath } from '../constants/PagePath';
@HMRouter({ pageUrl: PagePath.GAME_SETTINGS })
@Entry
@Component
export struct GameSettings {
@State minRange: number = 1;
@State maxRange: number = 100;
@State attemptsLimit: number = 10;
onConfirm() {
// 保存设置并返回
AppStorage.SetOrCreate('gameSettings', {
minRange: this.minRange,
maxRange: this.maxRange,
attemptsLimit: this.attemptsLimit
});
// 返回上一页
import { HMRouterMgr } from '@hadss/hmrouter';
HMRouterMgr.pop();
}
build() {
Column() {
Text('游戏设置')
.fontSize(24)
.margin({ bottom: 30 })
// 设置项...
Button('确定')
.onClick(() => this.onConfirm())
}
}
}
2. 修改主游戏页面,添加设置按钮
// 修改Index.ets,添加设置功能
@HMRouter({ pageUrl: PagePath.INDEX })
@Entry
@Component
export struct GuessNumberGame {
// 原有代码...
// 从AppStorage读取设置
private settings: any = AppStorage.Get('gameSettings') || { minRange: 1, maxRange: 100 };
onSettingsClick() {
import { HMRouterMgr } from '@hadss/hmrouter';
import { PagePath } from '../constants/PagePath';
HMRouterMgr.push({
pageUrl: PagePath.GAME_SETTINGS
});
}
build() {
Column() {
// 原有UI...
// 添加设置按钮
Row() {
Button('设置')
.onClick(() => this.onSettingsClick())
.margin({ top: 20 })
}
}
}
}
7.2 家族族谱应用的路由管理
本项目中的家族族谱应用展示了HMRouter在实际项目中的应用:
页面结构
// constants/PagePath.ets
export class PagePath {
static readonly FAMILY_TREE: string = "FamilyTree"
static readonly ADD_MEMBER: string = "AddMember"
static readonly EDIT_MEMBER: string = "EditMember"
}
主页面导航
// pages/FamilyTree.ets
@HMRouter({ pageUrl: PagePath.FAMILY_TREE })
@ComponentV2
export struct FamilyTreeView {
build() {
Column() {
// 页面内容...
// 导航到添加成员页面
Button('添加成员')
.onClick(() => {
HMRouterMgr.push({
pageUrl: PagePath.ADD_MEMBER
})
})
}
}
}
数据传递与状态管理
// 使用@Local装饰器管理组件本地状态
@HMRouter({ pageUrl: PagePath.ADD_MEMBER })
@ComponentV2
export struct AddMember {
@Local name: string = ''
@Local gender: 'male' | 'female' = 'male'
@Local birthDate: string = ''
build() {
// 表单内容...
}
}
8. 最佳实践与注意事项
8.1 路由管理最佳实践
-
统一管理页面路径:使用常量类统一管理所有页面路径,避免硬编码
// constants/PagePath.ets export class PagePath { static readonly INDEX = 'pages/Index'; static readonly DETAIL = 'pages/DetailPage'; static readonly SETTINGS = 'pages/SettingsPage'; } -
避免深层嵌套导航:设计合理的页面层级,避免过深的导航嵌套,影响用户体验
-
使用导航守卫处理通用逻辑:将登录检查、权限验证等通用逻辑放在导航守卫中
-
合理使用不同的跳转模式:根据场景选择push、replace或replaceAll
8.2 状态管理最佳实践
-
选择合适的装饰器:
- 组件内部状态使用@State
- 父子组件通信使用@Prop和@Link
- 跨组件状态共享使用@Provide/@Consume
- 全局状态使用@AppStorage
- 持久化状态使用@LocalStorage
-
合理使用@Local和@ComponentV2:
@ComponentV2 export struct MyComponent { @Local myState: string = 'initial value' build() { // 使用myState } } -
避免过度使用全局状态:只将真正需要全局共享的数据放入@AppStorage
8.3 常见问题与解决方案
-
路由参数传递失败
- 检查参数格式是否正确
- 确保目标页面正确接收参数
- 对于复杂对象,考虑使用序列化/反序列化
-
页面跳转后状态丢失
- 使用AppStorage或LocalStorage保存全局状态
- 在onPageShow生命周期中恢复页面状态
-
动画效果不符合预期
- 检查动画配置参数
- 避免在动画期间执行重计算操作
- 考虑使用默认动画配置进行调试
-
内存管理问题
- 在onDestroy生命周期中清理资源
- 避免在页面中持有过多的全局引用
- 对于长时间运行的应用,考虑定期清理导航栈
9. 总结
页面路由和导航是ArkTS应用开发的重要组成部分。通过掌握原生Router模块和HMRouter等第三方路由框架的使用,可以构建出用户体验良好的多页面应用。在实际开发中,应根据应用的复杂度和需求选择合适的路由方案,并遵循路由管理的最佳实践,确保应用的性能和稳定性。
通过本课程的学习,您应该能够熟练掌握ArkTS中的页面路由和导航技术,包括基本的页面跳转、参数传递、导航动画和路由守卫等功能,为开发复杂的HarmonyOS应用打下坚实的基础。同时,我们也介绍了ArkTS中的状态管理机制,帮助您更好地处理页面间的数据传递和状态同步。

1886

被折叠的 条评论
为什么被折叠?



