【高心星出品】
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
@Component
struct 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
*功能:
**/
@Component
export 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
})
复制代码
评论