🧩 一、核心概念:Navigation路由生命周期是什么?
在Navigation路由体系里,每个页面(NavDestination)从"出生"到"消失",会经历一系列自动触发的函数,我们称为生命周期。它们像闹钟一样,在特定节点提醒你该做什么操作,比如加载数据、清理资源等。和传统Router不同,NavDestination不走 onPageShow/onPageHide
,而是用自己专属的生命周期7。
⏳ 二、完整生命周期流程(时序与用途)
想象一个页面从打开到关闭的全过程:
sequenceDiagram
新页面->>当前页面: 新页面aboutToAppear组件创建,可初始化变量
新页面->>当前页面: 新页面onWillAppear即将显示,可改路由栈
新页面->>当前页面: 新页面onAppear已挂载显示
新页面->>当前页面: 新页面onShown完全展示,适合开启动画
当前页面-->>新页面: 当前页面onWillHide即将隐藏
当前页面-->>新页面: 当前页面onHidden完全隐藏
当前页面-->>新页面: 当前页面onWillDisappear即将销毁
当前页面-->>新页面: 当前页面onDisappear已销毁
新页面-)当前页面: 当前页面aboutToDisappear最终清理资源
关键阶段解析:
aboutToAppear
:页面"出生证",在这里初始化数据 🎯onReady
:唯一能拿到NavPathStack
路由栈对象的地方,用于后续跳转6onShown
:页面完全可见,适合开启动画或自动播放onHidden
:用户离开页面,暂停视频或计时器 ⏸️aboutToDisappear
:最后清理内存,注销监听事件 🧹
⚙️ 三、基础配置:路由表与页面注册
1. 路由表配置(route_map.json)
json
ruby
// src/main/resources/base/profile/route_map.json
{
"routerMap": [
{
"name": "detailPage", // 路由名称
"pageSourceFile": "pages/DetailPage.ets", // 文件路径
"buildFunction": "DetailBuilder" // 页面构建函数
}
]
}
2. Module注册(module.json5)
json
kotlin
{
"module": {
"routerMap": "$profile:route_map" // 指向路由表
}
}
3. 页面代码示例
typescript
scss
// DetailPage.ets
@Builder
export function DetailBuilder() { // 和路由表里的buildFunction一致
DetailComponent()
}
@Component
struct DetailComponent {
build() {
NavDestination() {
// 页面内容...
}
.onReady((ctx: NavDestinationContext) => {
const stack = ctx.pathStack; // 获取路由栈
stack.pushPath({ name: "nextPage" }); // 后续跳转
})
.onShown(() => {
console.log("页面已完全展示");
})
}
}
🚀 四、生命周期在典型场景中的应用
场景1:列表页进入详情页时暂停视频
typescript
scss
// 列表页
@Component
struct ListPage {
@State videoPlaying: boolean = true;
build() {
NavDestination() {
VideoPlayer().play($rawfile('video.mp4'))
}
.onHidden(() => {
this.videoPlaying = false; // 离开时暂停
})
.onShown(() => {
if (!this.videoPlaying) {
this.videoPlaying = true; // 返回时恢复播放
}
})
}
}
场景2:从不同页面返回时差异化刷新
typescript
ini
// 目标页:检查来源决定是否刷新
aboutToAppear() {
const routes = stack.getAllPathName();
const lastPage = routes[routes.length - 2]; // 上一个页面名
if (lastPage === "SettingsPage") { // 从设置页返回需刷新
this.refreshData();
}
}
场景3:避免重复创建资源(单例模式)
typescript
scss
let dataCache: DataType | null = null; // 全局缓存
@Component
struct DataPage {
aboutToAppear() {
if (!dataCache) {
dataCache = loadHeavyData(); // 只加载一次
}
}
aboutToDisappear() {
// 不清理缓存,下次复用
}
}
⚠️ 五、避坑指南:常见问题解决
-
生命周期不触发?
- 检查是否用
@Builder
函数包裹了组件(必须项)2 - 确认API版本≥12(旧版有兼容问题)2
- 检查是否用
-
路由跳转后页面卡顿?
- 在
aboutToDisappear
释放资源(如关闭数据库连接) - 避免在
onReady
执行耗时操作❌
- 在
-
根页面不触发
onPageShow
?- Navigation容器本身不是页面,用
onShown
代替onPageShow
7
- Navigation容器本身不是页面,用
🔍 六、对比:Navigation vs Router 的生命周期
能力 | Navigation (NavDestination) | Router (@Entry页面) |
---|---|---|
初始化 | aboutToAppear |
aboutToAppear |
页面显示 | onShown |
onPageShow |
页面隐藏 | onHidden |
onPageHide |
获取路由栈 | ✅ 通过onReady 的ctx.pathStack |
❌ 仅能获取当前页 |
跨设备状态同步 | ✅ 通过分布式API | ⚠️ 需手动实现 |
🧪 七、动手练习:完整示例
typescript
scss
// 主页:带跳转按钮
@Entry
@Component
struct HomePage {
private stack: NavPathStack = new NavPathStack();
build() {
Navigation(this.stack) {
Button("跳转到详情页")
.onClick(() => {
this.stack.pushPath({ name: "detailPage" });
})
}
}
}
// 详情页:记录生命周期
@Builder
export function DetailBuilder() {
DetailComponent()
}
@Component
struct DetailComponent {
@State eventLog: string = "";
build() {
NavDestination() {
Text(this.eventLog).fontSize(16)
}
.onAppear(() => { this.eventLog += "可见\n"; })
.onShown(() => { this.eventLog += "完全展示\n"; })
.onHidden(() => { this.eventLog += "隐藏\n"; })
.aboutToDisappear(() => {
showToast("页面即将关闭");
})
}
}
💎 最后总结 :
Navigation的生命周期是基于组件 而非页面,核心在于
onReady
(拿路由栈)、onShown
/onHidden
(代替传统显示/隐藏)、aboutToDisappear
(资源清理)。用好这几个节点,就能解决90%的路由状态管理问题。