写点什么

HarmonyOS 5.0 应用开发——Navigation 实现页面路由

作者:高心星
  • 2024-10-31
    江苏
  • 本文字数:3138 字

    阅读完需:约 10 分钟

HarmonyOS 5.0应用开发——Navigation实现页面路由

【高心星出品】


Navigation 实现页面路由

Navigation:路由导航的根视图容器,一般作为页面(@Entry)的根容器去使用,包括单页面(stack)、分栏(split)和自适应(auto)三种显示模式。Navigation 组件适用于模块内和跨模块的路由切换,通过组件级路由能力实现更加自然流畅的转场体验,并提供多种标题栏样式来呈现更好的标题和内容联动效果。一次开发,多端部署场景下,Navigation 组件能够自动适配窗口显示大小,在窗口较大的场景下自动切换分栏展示效果。



  1. Title:标题栏,通过 title 属性对标题栏进行设置。通过 menus 配置菜单

  2. NavContent:内容区域,默认首页显示导航内容(Navigation 的子组件)或非首页显示(NavDestination 的子组件),首页和非首页通过路由进行切换。

  3. ToolBar:工具栏,通过 toolbarConfiguration 实现对工具栏的配置,如果不配置此属性,ToolBar 不显示。竖屏最多支持显示 5 个图标,多余的图标会被放入自动生成的更多图标。

  4. NavDestination:作为子页面的根容器,用于显示 Navigation 的内容区。具备两种类型:STANDARD(标准类型,NavDestination 的生命周期跟随 NavPathStack 栈中标准 NavDestination 变化而改变),DIALOG(默认透明。不影响其他 NavDestination 的生命周期)。

  5. 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})
复制代码


用户头像

高心星

关注

天将降大任于斯人也,必先苦其心志。 2024-10-17 加入

华为开发者专家(HDE)。 10年教学经验,兼任多家科技公司技术顾问。先后从事JavaEE项目开发、Python爬虫、HarmonyOS移动应用开发等课程的教学工作。参与开发《鸿蒙应用开发基础》和《鸿蒙项目实战》等课程。

评论

发布
暂无评论
HarmonyOS 5.0应用开发——Navigation实现页面路由_鸿蒙_高心星_InfoQ写作社区