HarmonyOS 推荐使用 Navigation NavPathStack 实现页面导航相比传统ohos.router它支持更灵活的路由栈管理、动画控制和跨模块路由。柚兔学伴基于 NavPathStack 封装了PageContext自定义路由管理器配合router_map.json路由表和Builder页面注册构建了一套声明式、可回传数据的导航体系。一、Navigation NavPathStack 基础1.1 传统 router 的局限HarmonyOS 早期的ohos.router提供了router.pushUrl()/router.back()等接口但存在以下局限路由栈不透明无法灵活操作中间页面不支持自定义转场动画页面间数据回传需要通过 AppStorage 或全局变量中转无法实现 Tab 内子页面导航1.2 Navigation 的优势Navigation NavPathStack 是官方推荐的新一代导航方案特性ohos.routerNavigation NavPathStack路由栈操作push / backpush / pop / replace / clear / moveToTop 等数据回传无原生支持onReturn 回调机制转场动画有限自定义动画跨模块路由不支持routerMap 全局路由表导航模式单一Stack / Split 自适应二、PageContext 自定义路由管理器柚兔学伴封装了PageContext类对 NavPathStack 进行了业务层抽象// common/src/main/ets/routermanager/PageContext.etsexportinterfaceRouterParam{routerName:string;// 路由名称对应 router_map.json 中的 nameparam?:object;// 传递给目标页面的参数onReturn?:(data?:object)void;// 返回时的数据回调}exportinterfaceIPageContext{openPage(data:RouterParam,animated?:boolean):void;popPage(animated?:boolean):void;replacePage(data:RouterParam,animated?:boolean):void;}exportclassPageContextimplementsIPageContext{privatereadonlypathStack:NavPathStack;privatereturnCallback?:(data?:object)void;constructor(){this.pathStacknewNavPathStack();}publicopenPage(data:RouterParam,animated:booleantrue):void{try{this.returnCallbackdata.onReturn;// 保存返回回调this.pathStack.pushPath({name:data.routerName,param:data.param,},animated);}catch(err){Logger.error(TAG,Open Page${data.routerName}failed.);}}publicpopPage(animated:booleantrue,returnData?:object):void{try{if(this.returnCallback){this.returnCallback(returnData);// 执行返回回调this.returnCallbackundefined;}this.pathStack.pop(animated);}catch(err){Logger.error(TAG,Pop Page failed.);}}publicreplacePage(data:RouterParam,animated:booleantrue):void{try{this.pathStack.replacePath({name:data.routerName,param:data.param,},animated);}catch(err){Logger.error(TAG,Open Page${data.routerName}failed.);}}publicgetnavPathStack():NavPathStack{returnthis.pathStack;}}2.1 openPage页面跳转openPage封装了pushPath额外保存了onReturn回调pageContext.openPage({routerName:ChatPage,param:{waitingGif:/girl_wait.gif,speakingGif:/girl_speak.gif,gender:girl},onReturn:(data){// 处理 ChatPage 返回的数据console.info(ChatPage returned:,JSON.stringify(data));}});2.2 popPage页面返回popPage在执行pathStack.pop()前先调用returnCallback将数据回传给上一个页面// 在 ChatPage 中返回并传递数据this.pageContext.popPage(true,{lastMessage:再见});2.3 replacePage页面替换replacePage替换当前栈顶页面不产生新的历史记录pageContext.replacePage({routerName:MainPage,param:{tab:1}});三、PageContext 的创建与使用3.1 全局创建在EntryAbility.onWindowStageCreate中创建并存储到 AppStorage// entry/src/main/ets/entryability/EntryAbility.etsAppStorage.setOrCreate(pageContext,newPageContext());3.2 在主页中绑定 Navigation// entry/src/main/ets/pages/HomePage.etsEntryComponentV2struct HomePage{privatepageContext:PageContextAppStorage.get(pageContext)asPageContext;privateappPathInfo:NavPathStackthis.pageContext.navPathStack;build(){Navigation(this.appPathInfo){Column(){this.TabComponent()CustomTabBar({currentIndex:this.currentIndex,tabBarChange:(idx){this.currentIndexidx;}})}.height(100%).width(100%)}.hideTitleBar(true).mode(NavigationMode.Stack).height(100%).width(100%)}}关键点Navigation(this.appPathInfo)将 NavPathStack 绑定到 Navigation 组件NavigationMode.Stack使用栈管理模式支持 push/pop 导航hideTitleBar(true)隐藏 Navigation 自带标题栏使用自定义 TopBar四、router_map.json 路由表4.1 路由表配置每个模块在src/main/resources/base/profile/router_map.json中声明自己的路由// entry/src/main/resources/base/profile/router_map.json{routerMap:[{name:MainPage,pageSourceFile:src/main/ets/pages/MainPage.ets,buildFunction:MainPageBuilder},{name:TimerPage,pageSourceFile:src/main/ets/pages/TimerPage.ets,buildFunction:TimerPageBuilder}]}// feature/chat/src/main/resources/base/profile/router_map.json{routerMap:[{name:ChatPage,pageSourceFile:src/main/ets/view/ChatPage.ets,buildFunction:ChatPageBuilder},{name:WordCardPage,pageSourceFile:src/main/ets/view/WordCardPage.ets,buildFunction:WordCardPageBuilder},{name:SentenceCardPage,pageSourceFile:src/main/ets/view/SentenceCardPage.ets,buildFunction:SentenceCardPageBuilder}]}字段说明name路由名称即openPage({ routerName: ChatPage })中使用的标识符pageSourceFile页面组件源文件路径buildFunction页面构建函数名对应Builder导出函数4.2 各模块路由表总览模块路由名称说明entryMainPage, TimerPage主页、计时器页chatChatPage, WordCardPage, SentenceCardPage对话页、单词卡页、句子卡页todoPoemPage, CopyPage, TextbookPage, BookListPage, PdfViewerPage诗词页、抄写页、课本页、书列表页、PDF 阅读页strokeStrokePage笔画练习页myScorePage, WebPage, ExchangeListPage, SettingPage, AboutPage积分页、网页页、兑换列表页、设置页、关于页4.3 module.json5 引用路由表在module.json5中通过routerMap字段引用路由表// feature/chat/src/main/module.json5 { module: { name: chat, type: har, routerMap: $profile:router_map, // 引用路由表 deviceTypes: [default, tablet, 2in1] } }编译时各模块的路由表会自动合并到应用的全局路由注册表中实现跨模块路由跳转。五、Builder 页面注册与 NavDestination5.1 Builder 导出函数每个路由页面需要导出一个与buildFunction同名的Builder函数// feature/chat/src/main/ets/view/ChatPage.etsComponentstruct ChatPage{privatepageContext:PageContextAppStorage.get(pageContext)asPageContext;build(){NavDestination(){Column(){// 页面内容}}.hideTitleBar(true).onReady(async(cxt:NavDestinationContext){// 接收路由参数constdatacxt.pathInfo.paramasRecordstring,string|number|boolean;// 使用参数初始化页面});}}BuilderexportfunctionChatPageBuilder(){ChatPage()}关键步骤页面组件内部使用NavDestination作为根容器在NavDestination.onReady中接收路由参数导出Builder函数函数名必须与router_map.json中的buildFunction一致5.2 参数接收onReady回调的NavDestinationContext提供了pathInfo.param访问路由参数.onReady(async(cxt:NavDestinationContext){constdatacxt.pathInfo.paramasRecordstring,string|number|boolean;this.waitingUrldata.waitingGifasstring;this.speakingUrldata.speakingGifasstring;if(data.genderGender.GIRL){this.timbreBV421_streaming;}})参数类型与openPage时传入的param对象对应。5.3 页面返回在子页面中调用popPage返回主页Image($r(app.media.ic_back_white)).width(26).onClick((){this.pageContext.popPage(true);// 带动画返回})如需回传数据this.pageContext.popPage(true,{lastMessage:content});六、完整导航流程1. 用户在 HomePage 点击对话按钮 │ ▼ 2. 调用 pageContext.openPage({ routerName: ChatPage, param: { waitingGif, speakingGif, gender }, onReturn: (data) { 处理返回数据 } }) │ ▼ 3. PageContext.openPage() ├── 保存 onReturn 回调到 returnCallback └── pathStack.pushPath({ name: ChatPage, param: {...} }) │ ▼ 4. Navigation 根据 router_map.json 找到 ChatPageBuilder ├── 调用 ChatPageBuilder() 创建组件 └── ChatPage 的 NavDestination.onReady 接收 param │ ▼ 5. 用户在 ChatPage 点击返回按钮 │ ▼ 6. 调用 pageContext.popPage(true, returnData) ├── 执行 returnCallback(returnData) → 触发 HomePage 的 onReturn └── pathStack.pop(true) → 转场动画返回七、与传统 router 的对比// 传统 ohos.router 方式router.pushUrl({url:pages/ChatPage});// 无参数回传无动画控制路由栈不透明// Navigation PageContext 方式pageContext.openPage({routerName:ChatPage,param:{gender:girl},onReturn:(data){/* 处理返回数据 */}});// 声明式参数传递、原生数据回传、可控动画、透明路由栈Navigation 方案的核心优势路由栈透明pathStack支持获取栈长度、遍历路由、移除中间页面数据回传原生onReturn回调机制无需全局变量中转跨模块路由router_map.json自动合并feature 模块的页面可直接跳转动画可控所有导航操作支持animated参数模式自适应NavigationMode.Stack手机单栏NavigationMode.Split平板双栏小结柚兔学伴基于 Navigation NavPathStack 构建了完整的路由管理体系PageContext封装了 openPage/popPage/replacePage 三个核心操作并支持 onReturn 数据回传router_map.json实现了声明式路由注册与跨模块路由合并BuilderNavDestination实现了页面组件与路由的解耦。这一方案相比传统 router 更灵活、更强大是 HarmonyOS 应用导航的最佳实践。