【高心星出品】
Navigation 实现页面路由
Navigation:路由导航的根视图容器,一般作为页面(@Entry)的根容器去使用,包括单页面(stack)、分栏(split)和自适应(auto)三种显示模式。Navigation 组件适用于模块内和跨模块的路由切换,通过组件级路由能力实现更加自然流畅的转场体验,并提供多种标题栏样式来呈现更好的标题和内容联动效果。一次开发,多端部署场景下,Navigation 组件能够自动适配窗口显示大小,在窗口较大的场景下自动切换分栏展示效果。
Title:标题栏,通过 title 属性对标题栏进行设置。通过 menus 配置菜单
NavContent:内容区域,默认首页显示导航内容(Navigation 的子组件)或非首页显示(NavDestination 的子组件),首页和非首页通过路由进行切换。
ToolBar:工具栏,通过 toolbarConfiguration 实现对工具栏的配置,如果不配置此属性,ToolBar 不显示。竖屏最多支持显示 5 个图标,多余的图标会被放入自动生成的更多图标。
NavDestination:作为子页面的根容器,用于显示 Navigation 的内容区。具备两种类型:STANDARD(标准类型,NavDestination 的生命周期跟随 NavPathStack 栈中标准 NavDestination 变化而改变),DIALOG(默认透明。不影响其他 NavDestination 的生命周期)。
NavPathStack:Navigation 路由栈,由于管理 NavDestination 组件的路由跳转。推荐使用 NavPathStack 配合 navDestination 属性进行页面路由。
完整的 Navigation
要求入口页面必须是 Navigation 组件作为容器,子页面必须是 NavDestinnation 组件作为容器。由于我们将页面内容区的页面都添加了页面栈,所以在子页面拿到页面栈之后也可以实现子页面之间跳转。
入口页面
import { page1 } from '../viewmodel/page1'import { page2 } from '../viewmodel/page2'
@Entry@Componentstruct Index { // 菜单栏 private menuitems:NavigationMenuItem[]=[ { value:'菜单1', icon:'resources/base/media/startIcon.png', action:()=>{} }, { value:'菜单2', icon:'resources/base/media/startIcon.png', action:()=>{} } ] // 工具栏 private toolbaritems:ToolbarItem[]=[ { value:'工具1', icon:$r('app.media.startIcon'), action:()=>{} }, { value:'工具2', icon:$r('app.media.startIcon'), action:()=>{} }, { value:'工具3', icon:$r('app.media.startIcon'), action:()=>{} }, { value:'工具4', icon:$r('app.media.startIcon'), action:()=>{} } ] // 页面路由栈 @Provide('pathstack') pathstack:NavPathStack=new NavPathStack()
// 内容页 @Builder pagemap(pagename:string){ if(pagename=='page1'){ page1() }else if(pagename=='page2'){ page2() } }
build() { Navigation(this.pathstack){ Column({space:20}){ Text('page1').fontSize(28).padding(10).border({width:2,color:Color.Red}) .onClick(()=>{ this.pathstack.pushPath({name:'page1'}) }) .width('100%') Text('page2').fontSize(28).padding(10).border({width:2,color:Color.Red}) .onClick(()=>{ this.pathstack.pushPath({name:'page2'}) }) .width('100%') }.width('100%') .height('100%') .backgroundColor(Color.Gray) } // 标题栏 .title('主标题') // 菜单栏 .menus(this.menuitems) // 工具栏 .toolbarConfiguration(this.toolbaritems) // 内容页 .navDestination(this.pagemap)
}}
复制代码
子页面
/** *作者:gxx *时间:2024/10/24 10:13 *功能: **/@Componentexport struct page1 {// 子页面拿到页面栈@Consume('pathstack') pathstack:NavPathStack private menuitems: NavigationMenuItem[] = [ { value: '菜单1', icon: 'resources/base/media/startIcon.png', action: () => { } }, { value: '菜单2', icon: 'resources/base/media/startIcon.png', action: () => { } } ]
build() { NavDestination() { Column() { Text('page1').fontSize(28).fontWeight(FontWeight.Bolder) }.width('100%') .height('100%') .justifyContent(FlexAlign.Center)
}.title('页面标题') .menus(this.menuitems)
}}
复制代码
页面跳转
普通页面跳转
pushpath 和 replacepath 都可以实现页面跳转,他们的区别就是在页面栈中覆盖页面还是替换页面的区别,replacepath 无法实现 pop 回调,因为当前页在跳转的时候已经被销毁。
// 子页面之间也可以跳转this.pathstack.replacePath({name:'page1',onPop:(info)=>{console.log('gxxt ',JSON.stringify(info))}})this.pathstack.pushPath({name:'page1',onPop:(info)=>{console.log('gxxt ',JSON.stringify(info))}})
复制代码
这里面的 onpop 是可选参数,如果设置了意味着在目标页可以通过调用页面栈的 pop 方法回到当前页,并且将返回值带过来,相当于带返回值的跳转。
.onBackPressed(()=>{ this.pathstack.pop(result) return true })
复制代码
此处 result 为目标页返回给当前页的返回值。
跳转携带数据
跳转的时候可以携带数据,通过 param 可以设置这些数据,并在目标页中获取。
.onClick(()=>{ this.pathstack.pushPath({name:'page1',param:'来自首页的信息'})})
复制代码
这里携带了字符串类型的数据作为 param。
.onReady((cxt)=>{ let param= cxt.pathInfo.param as string promptAction.showToast({message:param})})
复制代码
可以在子页面的 NavDestination 的 onready 中获取携带过来的数据。
路由拦截
路由跳转中可以进行拦截处理,常用于路由重定向。比如主页面跳转到 page1 的时候,携带的数据为 page2,重定向到 page2.
.onClick(()=>{ this.pathstack.pushPath({name:'page1',param:'page2'})})
复制代码
在首页跳转到 page1 页面。
aboutToAppear(): void { // 设置拦截器 this.pathstack.setInterception({ willShow:(from:NavDestinationContext|NavBar,to:NavDestinationContext|NavBar)=> { // 回到主页面的时候to是navbar if (typeof to == 'string') { return } else { let cxt = to as NavDestinationContext // 如果跳转到page1 但是携带数据是page2 就跳转到page2 if (cxt.pathInfo.name == 'page1') { if (cxt.pathInfo.param == 'page2') { //移除page1 this.pathstack.pop() this.pathstack.pushPath({ name: 'page2',param:'pagex' }) } } } } })}
复制代码
在主页定义了页面栈的拦截器,只要跳转的目标是 page1 并且携带了数据 page2,就将 page1 移除,重定向到 page2,就相当于从主页直接跳转到了 page2.
其他的
在主页中可以设置标题为 mini 并关闭后退按钮,从而保持界面统一化。
.titleMode(NavigationTitleMode.Mini).hideBackButton(true)
复制代码
在子页中可以在生命周期方法 onReady 中拿到当前子页的上下文环境 context,里面包含了页面路由的相关信息。
.onReady((cxt)=>{ let param= cxt.pathInfo.param as string promptAction.showToast({message:param})})
复制代码
在子页中点击后退图标或者按后退键都是执行了 NavDestination 的 onBackpress 生命周期函数,我们可以重写该函数。
.onBackPressed(()=>{ this.pathstack.pop('gxx') return true})
复制代码
评论