Navigation 介绍

Navigation是路由容器组件,一般作为首页的根容器。Navigation组件主要包含导航页(NavBar)和子页(NavDestination)。导航页由标题栏(Titlebar,包含菜单栏menu)、内容区(Navigation子组件)和工具栏(Toolbar)组成,其中导航页可以通过hideNavBar属性进行隐藏,导航页不存在页面栈中,导航页和子页,以及子页之间可以通过路由操作进行切换。

总结一下

:::info

  • Navigation是一个容器组件,一般作为页面的根容器
  • Navigation组件主要包含导航页和子页
    • 导航页组成:标题栏、菜单栏、内容区(Navigation子组件)、工具栏组件
    • 子页组成:标题栏、菜单栏、内容区(NavDestination子组件)组成

:::

Navigation 入门案例

案例需求

  • 新建一个导航页(NavigationPage),导航页要求包含标题栏、菜单栏、工具栏、内容区
  • 新建一个子页(NavDestinationPage)
  • 点击导航页内容区按钮时,跳转到子页
  • 在子页内容区点击按钮时,跳转到导航页

代码实现

  • 导航页代码
import { NavDestinationPage } from './NavDestinationPage'

@Entry
@Component
struct NavgationPage {
  //导航页标题
  title:string = '导航页标题'
  
  //导航页菜单按钮
  menus: NavigationMenuItem[] = [
    {
      value: 'aaa',	//菜单标题
      icon: './image/star.png', //菜单图标
      action: () => {}	//菜单动作
    },
    {
      value: 'bbb', icon: './image/star.png', action: () => {}
    },
    {
      value: 'ccc', icon: './image/star.png', action: () => {}
    },
    {
      value: 'ddd', icon: './image/star.png', action: () => {}
    }
  ]
  
  //导航页工具栏
  toolbar: ToolbarItem[] = [
    {
      value: 'aaa', icon: './image/star.png', action: () => {}
    },
    {
      value: 'bbb', icon: './image/star.png', action: () => {}
    },
    {
      value: 'ccc', icon: './image/star.png', action: () => {}
    },
    {
      value: 'ddd', icon: './image/star.png', action: () => {}
    },
  ]
  
  //导航路由栈
  @Provide navPathStack: NavPathStack = new NavPathStack()

  @Builder
  NavigationRouter(name:string, params?:string){
    if (name === 'NavDestination'){
      NavDestinationPage()
    }
  } 

  build() {
    Navigation(this.navPathStack) {
      Column({ space: 15 }) {
        Text('Navigation内容区').fontSize(30)
        Button('点击跳转到子页')
          .onClick(() => {
             this.navPathStack.pushPathByName('NavDestination','aaa')
          })
      }
      .width('100%')
      .height('100%')
      .backgroundColor(Color.Pink)
    }
    .title(this.title)	//设置标题
    .menus(this.menus)	//设置菜单
    .toolbarConfiguration(this.toolbar)		//设置工具条
    .navDestination(this.NavigationRouter)	//设置子页面
    .titleMode(NavigationTitleMode.Mini)		//设置标题模式(Mini、Full)
    .hideBackButton(true) //隐藏返回键				//隐藏返回键
  }	
}
  • 子页代码
@Component
export struct NavDestinationPage {
  //导航路由栈
  @Consume navPathStack: NavPathStack

  //子页面标题
  @State title:string = '子页面标题'

  //子页菜单
  menus: NavigationMenuItem[] = [
    {
      value: 'aaa', icon: './image/star.png', action: () => {}
    },
    {
      value: 'bbb', icon: './image/star.png', action: () => {}
    },
    {
      value: 'ccc', icon: './image/star.png', action: () => {}
    }
  ]

  build() {
    NavDestination(){
      Column(){
          Text('NavDestination内容区').fontSize(30)
          Button('点击回到导航页')
            .onClick(()=>{
              this.navPathStack.pop()	//弹栈
            })
      }.width('100%').height('100%').backgroundColor(Color.Orange)
    }
    .title(this.title)		//设置子页标题
    .menus(this.menus)		//设置子页菜单
  }
}

Tabs+Navigation 实现页面导航

经常刷手机的朋友都知道,很多应用的主页都是下边一个工具栏,上边是标题栏 、菜单按钮,中间是显示的内容,点击内容区时跳转到更细节的页面。如:微信、美团、头条等各种App都是采用这种结构。

如下图所示

页面结构

想要实现以上的页面结构,我们可以采用Tabs+Navigation来实现

:::color4

  • Tabs:主要用于显示页面的底部导航栏(一级页面)
  • Navigation:作为点击底部导航栏时显示页面的容器(二级页面)
  • NavDestination:点击页面内容时跳转的细节页面(三级页面)

:::

下面是示意图

案例效果

接下来我们采用以上的页面结构来做一个简单的案例,案例需求如下

:::color4

  • 自定义底部导航栏:三个Tab选项(快速入门、课程学习、知识地图)
  • 快速入门页面:包含标题栏、内容区是一个List,ListItem是一个字符串,点击ListItem进入子页面
  • 快速入门子页面:每一个子页面包含标题栏、内容区,标题栏显示上一页被点击的ListItem字符串

:::

代码实现

为了让代码理解起来实现更加有条理,我们把代码实现步骤拆解一下,按照下面步骤来完成

:::success

  1. 首先使用Tabs自定义底部导航组件,点击底部导航能够切换导航页面
  2. 导航页面用了三个自定义组件,分别对应快速入门、课程学习、知识地图
    1. QuickStartPage 快速入门页面
    2. CourseLearning 课程学习页面
    3. KnowledgeMap 知识地图页面
  3. 完成QuickStartPage 快速入门页面
    1. 采用Navigation 作为根容器
    2. 点击页面内容时,跳转到 NavDestination 子页面
  4. 后面CourseLearningKnowledgeMap页面实现步骤模仿QuickStartPage即可

:::

首页底部导航栏

import { CourseLearning } from '../view/CourseLearning';
import { KnowledgeMap } from '../view/KnowledgeMap';
import { QuickStartPage } from '../view/QuickStartPage';

@Entry
@Component
struct Index {
  //当前选中页签索引
  @State currentIndex: number = 0
  //Tabs控制器
  private tabsController: TabsController = new TabsController();

  @Builder
  tabBuilder(title: string, targetIndex: number, selectedImg: Resource, normalImg: Resource) {
    Column() {
      Image(this.currentIndex == targetIndex ? selectedImg : normalImg)
        .size({ width: 24, height: 24 })
      Text(title)
        .fontColor(this.currentIndex === targetIndex ? '#0A59F7' : '#999999')
        .fontSize(10)
        .textAlign(TextAlign.Center)
        .lineHeight(14)
        .fontWeight(500)
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
    .alignItems(HorizontalAlign.Center)
    .onClick(() => {
      this.currentIndex = targetIndex
      this.tabsController.changeIndex(this.currentIndex)
    })
  }

  build() {
    Tabs({ controller: this.tabsController, barPosition: BarPosition.End }) {
      TabContent() {
        QuickStartPage()
      }.tabBar(this.tabBuilder('快速入门', 0, $r('app.media.ic_01_on'), $r('app.media.ic_01_off')))

      TabContent() {
        CourseLearning()
      }.tabBar(this.tabBuilder('课程学习', 1, $r('app.media.ic_02_on'), $r('app.media.ic_02_off')))

      TabContent() {
        KnowledgeMap()
      }.tabBar(this.tabBuilder('知识地图', 2, $r('app.media.ic_03_on'), $r('app.media.ic_03_off')))
    }.onChange((index) => {
      this.currentIndex = index
    })
    .scrollable(false)	//禁止页面滑动切换
    .animationDuration(0) //设置页面切换动画时长,0为关闭动画
  }
}

快速入门导航页

import { ListItemDetail } from './ListItemDetail';

@Component
export struct QuickStartPage {
  @State title: string = '快速入门'
  items: string[] = ['HarmonyOS', 'Android', 'IOS', 'MacOS', 'Windows', 'Linux','Open Euler']
  //页面栈
  @Provide navPathStack: NavPathStack = new NavPathStack()

  /**
   * 页面路由
   * @param name    页面名称
   * @param params  页面参数
   */
  @Builder
  NavgationRouter(name: string, params?: string) {
     if (name === 'ListItemDetail'){
       ListItemDetail()
     }
  }

  build() {
    Navigation(this.navPathStack) {
      Column() {
        List({ space: 12 }) {
          ForEach(this.items, (item: string, index: number) => {
            ListItem() {
              Text(item).fontSize(18).width('100%').height(50).padding(12)
            }.onClick(() => {
              this.navPathStack.pushPathByName('ListItemDetail', item)
            })
          })
        }.divider({ strokeWidth: 1, color: Color.Gray })
      }.width('100%').height('100%')
      .backgroundColor(Color.Pink)
    }
    .title(this.title)
    .mode(NavigationMode.Stack) //单栏模式
    .titleMode(NavigationTitleMode.Mini)  //标题模式小标题
    .hideBackButton(true)
    .navDestination(this.NavgationRouter)
  }
}

快速入门子页面

@Component
export struct ListItemDetail {
  @State title:string = ''
  @Consume navPathStack: NavPathStack

  aboutToAppear(): void {
    this.title = this.navPathStack.getParamByName('ListItemDetail')[0] as string
  }

  build() {
    NavDestination(){
      Column(){
        Text(`我是子页面: ${this.title}`)
      }.width('100%')
      .height('100%')
    }.title(this.title)
  }
}
Logo

纵情码海钱塘涌,杭州开发者创新动! 属于杭州的开发者社区!致力于为杭州地区的开发者提供学习、合作和成长的机会;同时也为企业交流招聘提供舞台!

更多推荐