鸿蒙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 实现页面路由。
自适应模式下,当页面宽度大于或等于一定阈值(API version 9 及以前是 520vp,API version 10 及以后是 600vp)时,Navigation 组件采用分栏模式;否则,采用单栏模式。

图 1 单页面布局示意图
将 mode 属性设置为 NavigationMode.Split,则 Navigation 组件为分栏显示模式,如下图所示。

图 2 分栏布局示意图
分栏模式组件导航的完整示例代码如下:
1) Demo.ets:
2) PageOne.ets:
3) PageTwo.ets:
4) PageThree.ets:

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

图 4 Mini模式标题栏显示效果
Mini 模式标题栏示例如下:

图 5 Full模式标题栏显示效果
Full模式标题栏示例代码如下:

图 6 设置了3个图标的菜单栏
设置了 3 个图标的菜单栏的示例代码如下:
图片也可以引用 resources 中的资源:
在竖屏中设置了 4 个图标的菜单栏的示例代码如下:

图 7 在竖屏中设置了4个图标的菜单栏显示效果
设置了 3 个图标的工具栏显示效果如下图所示:

图 8 设置了3个图标的工具栏显示效果
工具栏的示例代码如下:
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)