Navigation

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

Navigation组件的页面包含主页和内容页。主页由标题栏、内容区和工具栏组成,可在内容区中使用NavRouter子组件实现导航栏功能。内容页主要显示NavDestination子组件中的内容。

NavRouter是配合Navigation使用的特殊子组件,默认提供点击响应处理,不需要开发者自定义点击事件逻辑。NavRouter有且仅有两个子组件,其中第二个子组件必须是NavDestination。NavDestination是配合NavRouter使用的特殊子组件,用于显示Navigation组件的内容页。当开发者点击NavRouter组件时,会跳转到对应的NavDestination内容区。

设置页面显示模式

Navigation组件通过mode属性设置页面的显示模式。

  • 自适应模式

    Navigation组件默认为自适应模式,此时mode属性为NavigationMode.Auto。自适应模式下,当设备宽度大于520vp时,Navigation组件采用分栏模式,反之采用单页面模式。

    Navigation() {
      ...
    }
    .mode(NavigationMode.Auto)
    
  • 单页面模式

    图1 单页面布局示意图

    zh-cn_image_0000001511740532

    将mode属性设置为NavigationMode.Stack,Navigation组件即可设置为单页面显示模式。

    Navigation() {
      ...
    }
    .mode(NavigationMode.Stack)
    

    单页面1

  • 分栏模式

    图2 分栏布局示意图

    zh-cn_image_0000001562820845

    将mode属性设置为NavigationMode.Split,Navigation组件即可设置为分栏显示模式。

    @Entry
    @Component
    struct NavigationExample {
      @State TooTmp: ToolbarItem = {'value': "func", 'icon': "./image/ic_public_highlights.svg", 'action': ()=> {}}
      private arr: number[] = [1, 2, 3];
    
      build() {
        Column() {
          Navigation() {
            TextInput({ placeholder: 'search...' })
              .width("90%")
              .height(40)
              .backgroundColor('#FFFFFF')
    
            List({ space: 12 }) {
              ForEach(this.arr, (item:string) => {
                ListItem() {
                  NavRouter() {
                    Text("NavRouter" + item)
                      .width("100%")
                      .height(72)
                      .backgroundColor('#FFFFFF')
                      .borderRadius(24)
                      .fontSize(16)
                      .fontWeight(500)
                      .textAlign(TextAlign.Center)
                    NavDestination() {
                      Text("NavDestinationContent" + item)
                    }
                    .title("NavDestinationTitle" + item)
                  }
                }
              }, (item:string):string => item)
            }
            .width("90%")
            .margin({ top: 12 })
          }
          .title("主标题")
          .mode(NavigationMode.Split)
          .menus([
            {value: "", icon: "./image/ic_public_search.svg", action: ()=> {}},
            {value: "", icon: "./image/ic_public_add.svg", action: ()=> {}},
            {value: "", icon: "./image/ic_public_add.svg", action: ()=> {}},
            {value: "", icon: "./image/ic_public_add.svg", action: ()=> {}},
            {value: "", icon: "./image/ic_public_add.svg", action: ()=> {}}
          ])
          .toolbarConfiguration([this.TooTmp, this.TooTmp, this.TooTmp])
        }
        .height('100%')
        .width('100%')
        .backgroundColor('#F1F3F5')
      }
    }
    

    分栏

设置标题栏模式

标题栏在界面顶部,用于呈现界面名称和操作入口,Navigation组件通过titleMode属性设置标题栏模式。

  • Mini模式 普通型标题栏,用于一级页面不需要突出标题的场景。

    图3 Mini模式标题栏

    mini

    Navigation() {
      ...
    }
    .titleMode(NavigationTitleMode.Mini)
    
  • Full模式 强调型标题栏,用于一级页面需要突出标题的场景。

    图4 Full模式标题栏

    free1

    Navigation() {
      ...
    }
    .titleMode(NavigationTitleMode.Full)
    

设置菜单栏

菜单栏位于Navigation组件的右上角,开发者可以通过menus属性进行设置。menus支持Array<NavigationMenuItem>和CustomBuilder两种参数类型。使用Array<NavigationMenuItem>类型时,竖屏最多支持显示3个图标,横屏最多支持显示5个图标,多余的图标会被放入自动生成的更多图标。

图5 设置了3个图标的菜单栏

菜单栏2

let TooTmp: NavigationMenuItem = {'value': "", 'icon': "./image/ic_public_highlights.svg", 'action': ()=> {}}
Navigation() {
  ...
}
.menus([TooTmp,
  TooTmp,
  TooTmp])

图片也可以引用resources中的资源。

let TooTmp: NavigationMenuItem = {'value': "", 'icon': "resources/base/media/ic_public_highlights.svg", 'action': ()=> {}}
Navigation() {
  ...
}
.menus([TooTmp,
  TooTmp,
  TooTmp])

图6 设置了4个图标的菜单栏

菜单栏

let TooTmp: NavigationMenuItem = {'value': "", 'icon': "./image/ic_public_highlights.svg", 'action': ()=> {}}
Navigation() {
  ...
}
.menus([TooTmp,
  TooTmp,
  TooTmp,
  TooTmp])

设置工具栏

工具栏位于Navigation组件的底部,开发者可以通过toolbarConfiguration属性进行设置。

图7 工具栏

free3

let TooTmp: ToolbarItem = {'value': "func", 'icon': "./image/ic_public_highlights.svg", 'action': ()=> {}}
let TooBar: ToolbarItem[] = [TooTmp,TooTmp,TooTmp]
Navigation() {
  ...
}
.toolbarConfiguration(TooBar)

设置子页面的类型

NavDestination作为子页面的根容器,用于显示Navigation的内容区,其mode属性可以设置子页面的类型。

  • 标准类型

    NavDestination组件默认为标准类型,此时mode属性为NavDestinationMode.STANDARD。标准类型NavDestination的生命周期跟随NavPathStack栈中标准Destination变化而改变。

  • 弹窗类型

    图8 弹窗类型的页面示意图

    dialog_navdes_1

    将mode属性设置为NavDestinationMode.DIALOG,此时NavDestination组件是弹窗类型,整个组件透明。通过给组件添加背景等,实现想要的弹窗效果。

    // Index.ets
    @Component
    struct Page01 {
    
      @Consume('pageInfos') pageInfos: NavPathStack;
    
      build() {
        NavDestination() {
          Button('push Page01')
            .width('80%')
            .onClick(() => {
              this.pageInfos.pushPathByName('Page01', '');
            })
            .margin({top: 10, bottom: 10})
          Button('push Dialog01')
            .width('80%')
            .onClick(() => {
              this.pageInfos.pushPathByName('Dialog01', '');
            })
            .margin({top: 10, bottom: 10})
        }
        .title('Page01')
      }
    }
    
    @Component
    struct Dialog01 {
    
      @Consume('pageInfos') pageInfos: NavPathStack;
    
      build() {
        NavDestination() {
          Stack() {
            Column()
              .width('100%')
              .height('100%')
              .backgroundColor(Color.Gray)
              .opacity(0.1)
              .onClick(() => {
                this.pageInfos.pop();
              })
            // Add controls for business processing
            Column() {
              Text('Dialog01')
                .fontSize(30)
                .fontWeight(2)
              Button('push Page01')
                .width('80%')
                .onClick(() => {
                  this.pageInfos.pushPathByName('Page01', '');
                })
                .margin({top: 10, bottom: 10})
              Button('push Dialog01')
                .width('80%')
                .onClick(() => {
                  this.pageInfos.pushPathByName('Dialog01', '');
                })
                .margin({top: 10, bottom: 10})
              Button('pop')
                .width('80%')
                .onClick(() => {
                  this.pageInfos.pop();
                })
                .margin({top: 10, bottom: 10})
            }
            .padding(10)
            .width(250)
            .backgroundColor(Color.White)
            .borderRadius(10)
          }
        }
        .hideTitleBar(true)
        // Set the mode property of this NavDestination to DIALOG
        .mode(NavDestinationMode.DIALOG)
      }
    }
    
    @Entry
    @Component
    struct Index {
      @Provide('pageInfos') pageInfos: NavPathStack = new NavPathStack()
      isLogin: boolean = false;
    
      @Builder
      PagesMap(name: string) {
        if (name == 'Page01') {
          Page01()
        } else if (name == 'Dialog01') {
          Dialog01()
        }
      }
    
      build() {
        Navigation(this.pageInfos) {
          Button('push Page01')
            .width('80%')
            .onClick(() => {
              this.pageInfos.pushPathByName('Page01', '');
            })
        }
        .mode(NavigationMode.Stack)
        .titleMode(NavigationTitleMode.Mini)
        .title('主页')
        .navDestination(this.PagesMap)
      }
    }
    

    dialog_navdes_2