文章目录
- 前言
- 一、路由体系回顾
- 1.1 三个核心组件的关系
- 1.2 本项目路由配置
- 二、NavPathStack 常用方法
- 2.1 跳转方法
- 2.2 返回方法
- 三、页面间传参详解
- 3.1 传递参数(pushPathByName 第二个参数)
- 3.2 接收参数(在目标页中)
- 四、完整实战:三页面路由示例
- 4.1 页面结构
- 4.2 代码实现
- 五、NavDestination 生命周期
- 总结
前言
页面跳转是每个 App 的基础功能。HarmonyOS 提供了Navigation+NavDestination+NavPathStack三件套来管理页面路由。本项目从MainPage跳转到GasStationPage就使用了这套路由体系。
本篇详细讲解 NavPathStack 的各种方法,以及如何实现参数传递、返回值获取、路由拦截等进阶功能。
一、路由体系回顾
1.1 三个核心组件的关系
Navigation(路由容器) ├── 维护一个 NavPathStack(路由栈) ├── 渲染当前栈顶页面 └── NavDestination(具体的子页面) ├── 通过 @Builder 函数注册 └── 通过 pushPathByName 跳转到1.2 本项目路由配置
路由映射(自动扫描):GasStationPage.ets文件顶部导出了一个@Builder函数:
// GasStationPage.ets@BuilderexportfunctionGasStationPageBuilder(){GasStationPage();}配合route_map.json(或自动扫描)将'GasStationPage'名称映射到这个 Builder 函数。
跳转调用(MainPage):
// MainPage.etsRow(){// ...}.onClick(()=>{this.pageInfos.pushPathByName('GasStationPage',true);// ↑ 路由名称 ↑ 是否带动画})接收目标页(GasStationPage):
// GasStationPage.etsNavDestination(){// ... 页面内容}.onReady((context:NavDestinationContext)=>{// 获取路由栈(用于在子页面内部进行路由操作)this.pageInfos=context.pathStack;})二、NavPathStack 常用方法
2.1 跳转方法
// 创建路由栈(在 @Entry 页面中)constpathStack:NavPathStack=newNavPathStack();// 方式1:按名称跳转pathStack.pushPathByName('DetailPage',{id:'001',name:'望京站'});// 方式2:按名称跳转(带动画控制)pathStack.pushPathByName('DetailPage',null,false);// false = 不带动画// 方式3:跳转并等待返回值(async/await)constresult=awaitpathStack.pushPathByName('SelectPage',null,true);console.log(`返回值:${JSON.stringify(result)}`);// 获取 SelectPage 的返回结果// 方式4:替换当前页(不入栈,直接替换)pathStack.replacePath({name:'LoginPage',param:{}});// 方式5:跳转到路由栈中已有的页面(不重复入栈)pathStack.moveToTop('MainPage');2.2 返回方法
// 返回上一页pathStack.pop();// 返回上一页并传递结果pathStack.pop({status:'success',selectedId:'001'});// 返回到指定路由(弹出多层)pathStack.popToName('MainPage');// 清空路由栈(回到根页面)pathStack.clear();// 获取当前栈的深度constdepth=pathStack.size();// 栈中页面数量三、页面间传参详解
3.1 传递参数(pushPathByName 第二个参数)
// 跳转时传参pathStack.pushPathByName('StationDetailPage',{stationId:'001',stationName:'望京石化',latitude:40.0046,longitude:116.4823});3.2 接收参数(在目标页中)
@Componentstruct StationDetailPage{@StatestationId:string='';@StatestationName:string='';privatelatitude:number=0;privatelongitude:number=0;build(){NavDestination(){Column({space:16}){Text(`ID:${this.stationId}`)Text(`名称:${this.stationName}`)Text(`坐标:${this.latitude},${this.longitude}`)}.padding(24)}.onReady((context:NavDestinationContext)=>{// 获取路由参数constparams=context.pathInfo.paramasRecord<string,string|number>;this.stationId=params['stationId']asstring;this.stationName=params['stationName']asstring;this.latitude=params['latitude']asnumber;this.longitude=params['longitude']asnumber;}).title(this.stationName)}}四、完整实战:三页面路由示例
4.1 页面结构
MainListPage(列表页) ↓ pushPathByName('StationDetail', {id}) StationDetailPage(详情页) ↓ pushPathByName('MapPage', {lat, lng}) MapPage(地图页) ↓ pop({navigated: true}) StationDetailPage(接收返回值) ↓ pop() MainListPage4.2 代码实现
// ====== 根容器(app的最外层)======@Entry@Componentstruct AppRoot{@ProvidepageInfos:NavPathStack=newNavPathStack();@BuilderpageBuilder(name:string,param:Object){if(name==='StationDetail'){StationDetailPage()}elseif(name==='MapPage'){MapPage()}}build(){Navigation(this.pageInfos){MainListPage()}.navDestination(this.pageBuilder).hideNavBar(false).title('附近加油站').width('100%').height('100%')}}interfaceStationInfo{id:string;name:string;lat:number;lng:number;}interfaceMapParams{lat:number;lng:number;}// ====== 列表页 ======@Componentstruct MainListPage{@ConsumepageInfos:NavPathStack;// 从父级 Navigation 继承路由栈privatestations:StationInfo[]=[{id:'001',name:'望京石化',lat:40.0046,lng:116.4823},{id:'002',name:'朝阳石油',lat:39.9219,lng:116.4386},];build(){List({space:12}){ForEach(this.stations,(station:StationInfo)=>{ListItem(){Text(station.name).fontSize(16).padding(16).width('100%').backgroundColor('#FFFFFF').borderRadius(12).onClick(()=>{this.pageInfos.pushPathByName('StationDetail',station);})}})}.padding(16)}}// ====== 详情页 ======@Componentstruct StationDetailPage{@StatestationInfo:Record<string,string|number>={};pageInfos:NavPathStack=newNavPathStack();build(){NavDestination(){Column({space:16}){Text(`加油站:${this.stationInfo['name']asstring}`).fontSize(18).fontWeight(FontWeight.Bold)Button('查看地图').onClick(()=>{constparams:MapParams={lat:this.stationInfo['lat']asnumber,lng:this.stationInfo['lng']asnumber};this.pageInfos.pushPathByName('MapPage',params);})Button('返回列表').onClick(()=>{this.pageInfos.pop();})}.padding(24)}.onReady((context:NavDestinationContext)=>{this.pageInfos=context.pathStack;this.stationInfo=context.pathInfo.paramasRecord<string,string|number>;}).title(this.stationInfo['name']asstring||'详情')}}// ====== 地图页 ======@Componentstruct MapPage{@Statelat:number=0;@Statelng:number=0;pageInfos:NavPathStack=newNavPathStack();build(){NavDestination(){Column({space:16}){Text(`地图坐标:${this.lat.toFixed(4)},${this.lng.toFixed(4)}`).fontSize(16)Text('(这里放地图组件)').fontColor('#999999')Button('返回详情').onClick(()=>{// 返回并传递结果this.pageInfos.pop({navigated:true,timestamp:Date.now()});})}.padding(24).justifyContent(FlexAlign.Center)}.onReady((context:NavDestinationContext)=>{this.pageInfos=context.pathStack;constparams=context.pathInfo.paramasRecord<string,number>;this.lat=params['lat'];this.lng=params['lng'];}).title('地图视图')}}五、NavDestination 生命周期
NavDestination(){// 页面内容}.onReady((context:NavDestinationContext)=>{// ① 页面准备完成,可以获取路由参数this.pageInfos=context.pathStack;this.params=context.pathInfo.param;}).onWillAppear(()=>{// ② 页面将要出现(动画开始前)console.log('页面将要出现');}).onAppear(()=>{// ③ 页面已完全出现console.log('页面已出现');}).onWillDisappear(()=>{// ④ 页面将要消失(动画开始前)console.log('页面将要消失');}).onDisappear(()=>{// ⑤ 页面已消失console.log('页面已消失,可以清理资源');}).onBackPressed(()=>{// ⑥ 拦截返回键(返回 true = 已处理,不执行默认返回)if(this.hasUnsavedChanges){this.showSaveDialog();// 弹出保存对话框returntrue;// 阻止默认返回行为}returnfalse;// 允许正常返回})本项目中的生命周期:
// GasStationPage.etsNavDestination(){/* ... */}.onReady((context:NavDestinationContext)=>{this.pageInfos=context.pathStack;// 获取路由栈}).onWillAppear(()=>{// 页面将要显示时初始化地图this.init().then(()=>{setTimeout(()=>{this.isShow=true;// 500ms后显示弹窗},Constants.TIME);});})总结
Navigation 路由体系通过NavPathStack管理页面栈,pushPathByName跳转并传参,pop返回并传递结果,NavDestination的onReady回调接收参数。掌握路由栈的深度管理(push/pop/popToName/clear)和生命周期回调(onWillAppear/onWillDisappear/onBackPressed),你就能构建任意复杂的多页面应用。