核心概念:Navigation路由生命周期是什么

🧩 一、核心概念:Navigation路由生命周期是什么?

在Navigation路由体系里,每个页面(NavDestination)从"出生"到"消失",会经历一系列自动触发的函数,我们称为生命周期。它们像闹钟一样,在特定节点提醒你该做什么操作,比如加载数据、清理资源等。和传统Router不同,NavDestination不走 onPageShow/onPageHide,而是用自己专属的生命周期7。


⏳ 二、完整生命周期流程(时序与用途)

想象一个页面从打开到关闭的全过程:

sequenceDiagram 新页面->>当前页面: 新页面aboutToAppear组件创建,可初始化变量 新页面->>当前页面: 新页面onWillAppear即将显示,可改路由栈 新页面->>当前页面: 新页面onAppear已挂载显示 新页面->>当前页面: 新页面onShown完全展示,适合开启动画 当前页面-->>新页面: 当前页面onWillHide即将隐藏 当前页面-->>新页面: 当前页面onHidden完全隐藏 当前页面-->>新页面: 当前页面onWillDisappear即将销毁 当前页面-->>新页面: 当前页面onDisappear已销毁 新页面-)当前页面: 当前页面aboutToDisappear最终清理资源

关键阶段解析

  • aboutToAppear:页面"出生证",在这里初始化数据 🎯
  • onReady :唯一能拿到 NavPathStack 路由栈对象的地方,用于后续跳转6
  • onShown:页面完全可见,适合开启动画或自动播放
  • 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() {
    // 不清理缓存,下次复用
  }
}

⚠️ 五、避坑指南:常见问题解决

  1. 生命周期不触发?

    • 检查是否用 @Builder 函数包裹了组件(必须项)2
    • 确认API版本≥12(旧版有兼容问题)2
  2. 路由跳转后页面卡顿?

    • aboutToDisappear 释放资源(如关闭数据库连接)
    • 避免在 onReady 执行耗时操作❌
  3. 根页面不触发 onPageShow

    • Navigation容器本身不是页面,用 onShown 代替 onPageShow7

🔍 六、对比:Navigation vs Router 的生命周期

能力 Navigation (NavDestination) Router (@Entry页面)
初始化 aboutToAppear aboutToAppear
页面显示 onShown onPageShow
页面隐藏 onHidden onPageHide
获取路由栈 ✅ 通过onReadyctx.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%的路由状态管理问题。

相关推荐
Solara11 分钟前
中文字体子集化实录:3.2MB → 200KB 的完整脚本、踩坑清单与三条反直觉经验
前端·css·架构
Htr_25 分钟前
Cortex 使用指南:开源 API 知识层
前端·数据库·人工智能·重构·计算机外设
计算机魔术师28 分钟前
Dario Amodei 发文呼吁 AI 行业放慢前沿速度并公布三步计划
前端
EatFan33 分钟前
前后端分离项目中 Token 到底应该怎么设计?Access Token + Refresh Token 实战
java·前端·后端
dsyyyyy110140 分钟前
Typescript装饰器
前端·javascript·typescript
一拳不是超人2 小时前
一个没测暗色模式的 Bug,吃掉了我一半 谷歌扩展用户
前端·javascript·程序员
liangshanbo12152 小时前
React useState 函数式更新面试题整理
前端·react.js·前端框架
涛涛ing2 小时前
为什么你的页面在 Safari 上总出问题?Interop 2027 正在解决这个 20 年老毛病
前端
不一样的少年_2 小时前
WebP 压缩到底在干嘛?小白也能看懂的原理拆解
前端·后端·图片资源
问心无愧05132 小时前
ctf show web 177
前端·笔记