首页 > 编程笔记 > 通用技能 阅读:1

鸿蒙Navigation组件用法详解(附带实例)

Navigation 是路由导航的根视图容器,通常作为页面(@Entry)的根容器,支持单栏(Stack)、分栏(Split)和自适应(Auto)三种显示模式。

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

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

在 API Version 9 上,Navigation 需要配合 NavRouter 组件实现页面路由。从 API Version 10 开始,推荐使用 NavPathStack 实现页面路由。

设置页面显示模式

Navigation 组件通过 mode 属性设置页面的显示模式。默认情况下,Navigation 组件使用自适应模式,此时 mode 属性为 NavigationMode.Auto。

自适应模式下,当页面宽度大于或等于一定阈值(API version 9 及以前是 520vp,API version 10 及以后是 600vp)时,Navigation 组件采用分栏模式;否则,采用单栏模式。
Navigation() {
// ...
}.mode(NavigationMode.Auto)
将 mode 属性设置为 NavigationMode.Stack,则 Navigation 组件为单页面显示模式,如下图所示。


图 1 单页面布局示意图

将 mode 属性设置为 NavigationMode.Split,则 Navigation 组件为分栏显示模式,如下图所示。


图 2 分栏布局示意图

分栏模式组件导航的完整示例代码如下:
1) Demo.ets:
@Entry
@Component
struct NavigationExample {
  // 指定工具栏项目
  @State toolTmp: ToolbarItem = {
    value: 'func',               // 按钮的名称
    icon: 'image/highlight.png', // 按钮的图标
    action: () => {              // 按钮点击后指定的操作
    }
  };

  // Navigation 的路由栈,页面通过压栈的方式显示,同时该类提供了控制栈中页面的方法
  // 只有栈顶的页面是当前显示的页面
  // 同时与子组件共享 NavPathStack 状态
  @Provide('pageInfos') pageInfos: NavPathStack = new NavPathStack();
  private arr: number[] = [1, 2, 3];

  /**
   * 根据传递名称的不同,创建和显示不同子页
   * @param name 页面名称
   */
  @Builder
  pageMap(name: string) {
    if (name === 'NavDestinationTitle1') {
      PageOne();
    } else if (name === 'NavDestinationTitle2') {
      PageTwo();
    } else if (name === 'NavDestinationTitle3') {
      PageThree();
    }
  }

  build() {
    Column() {
      // 导航组件,设置路由栈
      Navigation(this.pageInfos) {
        TextInput({ placeholder: 'search...' })
          .width('90%')
          .height(40)
          .backgroundColor('#FFFFFF');

        List({ space: 12 }) {
          // 使用 ForEach 的方式为页面添加跳转的按钮
          ForEach(this.arr, (item: number) => {
            ListItem() {
              Text('NavRouter' + item)
                .width('100%')
                .height(72)
                .backgroundColor('#FFFFFF')
                .borderRadius(24)
                .fontSize(16)
                .fontWeight(500)
                .textAlign(TextAlign.Center)
                .onClick(() => {
                  // 当点击按钮时,将对应子页 NavPathInfo 实例压栈
                  // pushPath 还有第二个参数,表示是否使用动画展示对应的子页,默认值为 true,表示使用动画
                  this.pageInfos.pushPath({ name: 'NavDestinationTitle' + item });
                });
            }
          }, (item: number) => item.toString());
        }
        .width('90%')
        .margin({ top: 12 });
      }
      .title('主标题')                       // 设置主标题
      .mode(NavigationMode.Split)          // 设置显示模式为分栏模式
      .navDestination(this.pageMap)        // 设置用户定义的子页组件
      .menus([
        // 单独呈现的搜索按钮
        { value: '', icon: 'image/search.png', action: () => {} },
        // 单独呈现的添加按钮
        { value: '', icon: 'image/add.png', action: () => {} },
        // 折叠起来的添加按钮
        { value: '', icon: 'image/add.png', action: () => {} },
        // 折叠起来的添加按钮
        { value: '', icon: 'image/add.png', action: () => {} },
        // 折叠起来的添加按钮
        { value: '', icon: 'image/add.png', action: () => {} }
      ])
      // 在配置工具栏的时候,直接使用了 3 个 toolTmp 项目
      // 在真正的应用场景中,工具栏项目肯定不会是相同的 3 个项目
      // 图标、标题以及功能一般都会不同
      .toolbarConfiguration([this.toolTmp, this.toolTmp, this.toolTmp])
    }
    .height('100%')
    .width('100%')
    .backgroundColor('#F1F3F5');
  }
}

2) PageOne.ets:
@Component
export struct PageOne {
  // 与父组件共享 NavPathStack 状态
  @Consume('pageInfos') pageInfos: NavPathStack;

  build() {
    NavDestination() {
      Column() {
        Text('NavDestinationContent1');
      }
      .width('100%')
      .height('100%');
    }
    .title('NavDestinationTitle1')
    .onBackPressed(() => {
      // 当与 Navigation 绑定的页面栈中存在内容时,此回调生效。当点击返回键时,触发该回调
      // 返回值为 true 时,表示重写返回键逻辑;返回值为 false 时,表示回退到上一个页面
      // 此处之所以返回 true,是因为此处页面要退回到由 NavPathStack 指定的页面
      // 弹出路由栈的栈顶元素
      const popDestinationInfo = this.pageInfos.pop();
      console.log('pop 返回值 ' + JSON.stringify(popDestinationInfo));
      return true;
    });
  }
}

3) PageTwo.ets:
@Component
export struct PageTwo {
  // 与父组件共享 NavPathStack 状态
  @Consume('pageInfos') pageInfos: NavPathStack;

  build() {
    NavDestination() {
      Column() {
        Text('NavDestinationContent2');
      }
      .width('100%')
      .height('100%');
    }
    .title('NavDestinationTitle2')
    .onBackPressed(() => {
      // 当与 Navigation 绑定的页面栈中存在内容时,此回调生效。当点击返回键时,触发该回调
      // 返回值为 true 时,表示重写返回键逻辑;返回值为 false 时,表示回退到上一个页面
      // 此处之所以返回 true,是因为此处页面要退回到由 NavPathStack 指定的页面
      // 弹出路由栈的栈顶元素
      const popDestinationInfo = this.pageInfos.pop();
      console.log('pop 返回值 ' + JSON.stringify(popDestinationInfo));
      return true;
    });
  }
}

4) PageThree.ets:
@Component
export struct PageThree {
  // 与父组件共享 NavPathStack 状态
  @Consume('pageInfos') pageInfos: NavPathStack;

  build() {
    NavDestination() {
      Column() {
        Text('NavDestinationContent3');
      }
      .width('100%')
      .height('100%');
    }
    .title('NavDestinationTitle3')
    .onBackPressed(() => {
      // 当与 Navigation 绑定的页面栈中存在内容时,此回调生效。当点击返回键时,触发该回调
      // 返回值为 true 时,表示重写返回键逻辑;返回值为 false 时,表示回退到上一个页面
      // 此处之所以返回 true,是因为此处页面要退回到由 NavPathStack 指定的页面
      // 弹出路由栈的栈顶元素
      const popDestinationInfo = this.pageInfos.pop();
      console.log('pop 返回值 ' + JSON.stringify(popDestinationInfo));
      return true;
    });
  }
}
显示效果如下图所示:


图 3 分栏模式组件导航的显示效果

Navigation设置标题栏模式

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

Mini 模式表示普通型标题栏,适用于一级页面不需要突出标题的场景。Mini 模式标题栏显示效果如下图所示:


图 4 Mini模式标题栏显示效果

Mini 模式标题栏示例如下:
Navigation() {
// ...
}.titleMode(NavigationTitleMode.Mini)
Full 模式表示强调型标题栏,适用于一级页面需要突出标题的场景。Full 模式标题栏显示效果如下图所示。


图 5 Full模式标题栏显示效果

Full模式标题栏示例代码如下:
Navigation() {
  // ...
}.titleMode(NavigationTitleMode.Full)

Navigation设置菜单栏

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


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

设置了 3 个图标的菜单栏的示例代码如下:
let toolTmp: NavigationMenuItem = {'value': "", 'icon': "image/highlight.png", 'action':
()=> {}}
Navigation() {
  // ...
}.menus([toolTmp,  toolTmp,  toolTmp])

图片也可以引用 resources 中的资源:
let toolTmp: NavigationMenuItem = {'value': "", 'icon':"resources/base/media/highlight.png", 'action': ()=> {}}
Navigation() {
  // ...
}.menus([toolTmp,  toolTmp,  toolTmp])

在竖屏中设置了 4 个图标的菜单栏的示例代码如下:
let TooTmp: NavigationMenuItem = {'value': "", 'icon': "./image/ic_public_highlights.svg",     ?'action': ()=> {}}
'action': ()=> {}}
Navigation() {
  // ...
}.menus([TooTmp,  TooTmp,  TooTmp,  TooTmp])
显示效果如下图所示:


图 7 在竖屏中设置了4个图标的菜单栏显示效果

Navigation设置工具栏

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

设置了 3 个图标的工具栏显示效果如下图所示:


图 8 设置了3个图标的工具栏显示效果

工具栏的示例代码如下:
let toolTmp: ToolbarItem = {'value': "func", 'icon': "image/highlight.png", 'action': ()=>{}}
let toolBar: ToolbarItem[] = [toolTmp,toolTmp,toolTmp]
Navigation() {
  // ...
}.toolbarConfiguration(TooBar)

相关文章