news 2026/10/9 5:24:33

【ArkUI 练中学】第16课:导航与多页面应用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【ArkUI 练中学】第16课:导航与多页面应用

本节目标

· 掌握 Navigation 组件的完整架构:NavBar、NavDestination、NavPathStack 的职责与协作方式
· 理解 Navigation 的单栏、分栏、自适应三种显示模式,能够根据设备宽度自动切换布局
· 掌握 Tabs 选项卡的基础用法,包括 TabContent 与 tabBar 的配合、自定义 tabBar 的实现
· 掌握 SideBarContainer 侧边栏容器的 Embed 与 Overlay 两种显示模式,能够实现抽屉式导航
· 了解多页面应用的路由架构设计原则,能够为中等规模应用规划合理的页面组织方式
· 能够综合运用 Navigation、Tabs、SideBarContainer 构建一个完整的多页面应用骨架

一、Navigation 完整架构

1.1 三大核心概念

Navigation 组件是 ArkUI 推荐的组件级路由方案,其整体架构由三个核心部分组成。

Navigation(导航根视图容器) :所有的导航页面都被此容器包裹,提供分栏显示的能力,一般用作全局的根容器。Navigation 管理了标题栏、内容区和工具栏,内容区用于显示用户自定义页面的内容,并支持页面的路由能力。

NavDestination(子页面容器) :导航的所有页面路由操作均是针对 NavDestination 的操作。NavDestination 是 Navigation 子页面的根容器,用于承载子页面的特殊属性和生命周期,可以配置独立的标题栏、菜单栏与工具栏等属性,使用方法与 Navigation 一致。

NavPathStack(导航控制器) :用于管理 NavDestination 页面栈,封装了各种控制页面跳转的接口,支持继承后重写,需与 Navigation 绑定使用。整个 Navigation 容器应复用同一个 NavPathStack,不要在每次 build 或点击时重新创建。

1.2 单栏、分栏与自适应模式

Navigation 提供三种显示模式,通过 mode 属性控制。

单栏模式(Stack) :当 Navigation 容器宽度小于 600vp 时建议使用。此模式下发生路由跳转时,整个页面都会被替换。

分栏模式(Split) :当 Navigation 容器宽度大于等于 600vp 时建议使用。此模式下 Navigation 分为左右两部分,左侧为导航栏(NavBar),右侧为子页面(NavDestination)。发生路由跳转时,只有右边子页会被替换。

自适应模式(Auto) :默认值。在该模式下会自动监听屏幕属性,当为折叠屏或平板时默认分栏显示,在折叠状态或普通手机时可为单栏显示。

1.3 基础用法示例

以下是一个带完整路由跳转能力的 Navigation 示例:

@Entry@Componentstruct NavigationBasic{@Provide('pageStack')pageStack:NavPathStack=newNavPathStack()@BuilderpageMap(name:string,param:object){if(name==='detail'){DetailPage({itemId:paramasstring})}}build(){Navigation(this.pageStack){// NavBar 内容区:首页Column({space:16}){Text('首页').fontSize(24).fontWeight(FontWeight.Bold)ForEach(['商品A','商品B','商品C'],(item:string)=>{Row(){Text(item).fontSize(16).layoutWeight(1)Text('查看 →').fontSize(14).fontColor('#007DFF')}.width('100%').padding(16).backgroundColor(Color.White).borderRadius(10).onClick(()=>{this.pageStack.pushPathByName('detail',item)})})}.width('100%').height('100%').padding(16).backgroundColor('#F5F5F5')}.title('我的应用').mode(NavigationMode.Auto)// 自适应模式.navDestination(this.pageMap).hideNavBar(false)}}@Componentstruct DetailPage{@Consume('pageStack')pageStack:NavPathStack itemId:string=''build(){NavDestination(){Column({space:20}){Text(`详情页:${this.itemId}`).fontSize(22)Text('这里是子页面内容区域').fontSize(15).fontColor('#666')Button('返回').type(ButtonType.Capsule).onClick(()=>{this.pageStack.pop()})}.width('100%').height('100%').justifyContent(FlexAlign.Center)}.title('详情')}}

关键理解:@Provide 和 @Consume 实现 NavPathStack 的跨组件共享,避免在多个组件间逐层传递。navDestination 方法将页面名称映射到具体的 NavDestination 组件。跳转时 pushPathByName 传入名称和参数,子页面通过 pathInfo.param 或构造参数接收。

1.4 NavPathStack 常用操作

入栈:pushPathByName(name, param) 携带参数跳转;pushPathByName(name, param, onPop) 带返回回调的跳转。返回结果不要写全局变量,可在 pop 时带 result,或由共享 ViewModel 保存业务状态。

出栈:pop() 返回上一页;popToName(name) 返回指定页面;popToIndex(index) 返回到指定索引的页面。

替换:replacePath(info) 或 replacePathByName(name, param) 替换当前页面。

清空:clear() 清空路由栈。

路由拦截:支持通过 setInterception 做路由拦截。

二、Tabs 选项卡

2.1 基础结构

Tabs 组件通过页签进行内容视图切换,每个页签对应一个内容视图。Tabs 的页面组成包含两个部分:TabContent(内容页)和 TabBar(导航页签栏)。根据不同的导航类型,布局可以分为底部导航、顶部导航、侧边导航,其导航栏分别位于底部、顶部和侧边。

@Entry@Componentstruct TabsBasic{@StatecurrentIndex:number=0build(){Tabs({barPosition:BarPosition.End,index:this.currentIndex}){TabContent(){Column(){Text('首页内容').fontSize(24)}.width('100%').height('100%').justifyContent(FlexAlign.Center)}.tabBar(this.tabBuilder('首页',0))TabContent(){Column(){Text('发现内容').fontSize(24)}.width('100%').height('100%').justifyContent(FlexAlign.Center)}.tabBar(this.tabBuilder('发现',1))TabContent(){Column(){Text('我的内容').fontSize(24)}.width('100%').height('100%').justifyContent(FlexAlign.Center)}.tabBar(this.tabBuilder('我的',2))}.onChange((index:number)=>{this.currentIndex=index}).barHeight(56).width('100%').height('100%')}@BuildertabBuilder(title:string,index:number){Column({space:4}){Image(this.currentIndex===index?$r('app.media.icon_tab_active'):$r('app.media.icon_tab_normal')).width(24).height(24)Text(title).fontSize(11).fontColor(this.currentIndex===index?'#007DFF':'#999999')}.width('100%').height(56).justifyContent(FlexAlign.Center)}}

关键规则:TabContent 组件不支持设置通用宽度属性,其宽度默认撑满 Tabs 父组件;不支持设置通用高度属性,其高度由 Tabs 父组件高度与 TabBar 组件高度决定。每一个 TabContent 对应的内容需要有一个页签,可以通过 tabBar 属性进行配置。

2.2 自定义 TabBar

标准 Tabs 组件不支持在 tabBar 中添加其他组件(如“+”号按钮),但通过设置 barHeight(0) 隐藏原生 TabBar,再使用 Stack 将自定义 tabBar 放到上层即可实现。自定义 Tabs 的典型场景包括:在 tabBar 中添加操作按钮、实现可滚动的标签栏、创建完全自定义样式的导航栏。

// 自定义 tabBar 的核心思路Stack({alignContent:Alignment.TopStart}){// 自定义 tabBar 区域Scroll(){Row(){ForEach(this.tabArray,(item:number,index:number)=>{this.tab('Tab'+item,item,index)})Text('+').width(36).height(50).fontSize(28).onClick(()=>{this.tabArray.push(++this.lastTabIndex)})}}.scrollable(ScrollDirection.Horizontal).scrollBar(BarState.Off)// Tabs 内容区,barHeight(0) 隐藏原生 tabBarTabs({barPosition:BarPosition.Start,controller:this.controller}){ForEach(this.tabArray,(item:number)=>{TabContent(){Text('页面 '+item).fontSize(30)}})}.barHeight(0)}

2.3 Tabs 与滚动容器的双向联动

从 API 13 起,UIContext.bindTabsToScrollable() 可以将 TabsController 和 Scroll/List/Grid 的 Scroller 绑定起来:内容上滑时自动隐藏 TabBar,下滑时自动显示。

// 在 UIContext 中绑定this.getUIContext().bindTabsToScrollable(this.tabsController,this.scroller)this.getUIContext().bindTabsToNestedScrollable(this.tabsController,this.nestedScroller)

三、SideBarContainer 侧边栏容器

3.1 基本结构与显示模式

SideBarContainer 提供侧边栏可以显示和隐藏的容器,通过子组件定义侧边栏和内容区。第一个子组件表示侧边栏,第二个子组件表示内容区,必须且仅包含 2 个子组件。

SideBarContainer 支持两种显示模式:

Embed(并排式) :侧边栏嵌入到组件内,和内容区并列显示,适用于需要同时展示侧边栏和内容区的场景(平板、PC 大屏)。整体容器大小不变时,显示侧边栏会导致内容区缩小,隐藏侧边栏会扩大内容区。

Overlay(覆盖式) :侧边栏覆盖在内容区上方,不影响内容区布局,适用于手机等小屏设备。侧边栏隐藏时不占据空间,唤出时悬浮在内容之上。

@Entry@Componentstruct SideBarDemo{@StateshowSideBar:boolean=truebuild(){SideBarContainer(SideBarContainerType.Embed){// 第一个子组件:侧边栏Column({space:12}){Text('导航菜单').fontSize(18).fontWeight(FontWeight.Bold).margin({bottom:12})ForEach(['首页','发现','消息','设置'],(item:string,index:number)=>{Row({space:12}){Text(item).fontSize(15)}.width('100%').padding(12).borderRadius(8).backgroundColor(index===0?'#E8F0FE':Color.Transparent)})}.width(220).height('100%').padding(16).backgroundColor('#F8F9FA')// 第二个子组件:内容区Column(){Text('主内容区域').fontSize(24)}.width('100%').height('100%').justifyContent(FlexAlign.Center)}.showSideBar(this.showSideBar).showControlButton(true)// 显示控制按钮.sideBarWidth(220).minSideBarWidth(180).minContentWidth(360).onChange((value:boolean)=>{this.showSideBar=value}).width('100%').height('100%')}}

3.2 关键属性

showSideBar:设置是否显示侧边栏,默认为 true。

sideBarWidth / minSideBarWidth / maxSideBarWidth:控制侧边栏宽度。组件尺寸小于 minContentWidth + minSideBarWidth 且未设置 showSideBar 时,侧边栏自动隐藏。

showControlButton:是否显示控制按钮,默认为 true。可以通过 controlButton 属性自定义控制按钮的图标和位置。

sideBarPosition:设置侧边栏的位置,可选 Start(左侧)或 End(右侧)。

四、多页面架构设计建议

4.1 页面数量增长带来的问题

在 HarmonyOS 项目中,页面数量一旦超过 5 个,如果没有清晰的多页面架构设计,很快就会出现以下问题:路由混乱,页面之间互相跳转像“意大利面”;页面状态靠参数硬传,改一个页面牵一片;生命周期逻辑分散,难以统一管理;后期加新功能,不敢动老代码。

4.2 推荐的架构组织方式

根容器用 Navigation:将 Navigation 作为应用根容器,所有页面跳转通过 NavPathStack 管理。Navigation 具备更强的一次开发多端部署能力,可以进行更加灵活的页面栈操作,同时支持更丰富的动效和生命周期。

主页面用 Tabs:应用的主框架(首页、发现、消息、我的)用 Tabs 组织,每个 Tab 内部再嵌套 Navigation 实现该 Tab 下的页面跳转。

设置页面用 SideBarContainer:如果应用有侧边菜单需求(如设置、帮助中心),使用 SideBarContainer 或 Navigation 的分栏模式实现。

跨模块跳转用 Router:如果项目包含多个模块(HAP),主项目要跳转到其他模块的页面时,使用 Router 实现跨模块跳转。单模块应用推荐全部使用 Navigation。

4.3 综合架构示例

@Entry@Componentstruct AppRoot{@Provide('mainStack')mainStack:NavPathStack=newNavPathStack()@BuilderpageMap(name:string){if(name==='settings'){SettingsPage()}elseif(name==='profile'){ProfilePage()}}build(){Navigation(this.mainStack){// 主框架:TabsTabs({barPosition:BarPosition.End}){TabContent(){HomePage()}.tabBar(this.mainTab('首页',0))TabContent(){DiscoverPage()}.tabBar(this.mainTab('发现',1))TabContent(){MessagePage()}.tabBar(this.mainTab('消息',2))TabContent(){ProfilePage()}.tabBar(this.mainTab('我的',3))}.barHeight(56)}.title('应用名称').mode(NavigationMode.Auto).navDestination(this.pageMap).hideNavBar(false)}@BuildermainTab(title:string,index:number){Column({space:4}){Text(title).fontSize(11).fontColor(this.currentTabIndex===index?'#007DFF':'#999')}.width('100%').height(56).justifyContent(FlexAlign.Center)}}

五、多元化习题

习题 1(判断题)

题目:在 Navigation 架构中,NavPathStack 可以在每次点击跳转时重新创建,不影响路由功能。

答案:错误

解读:整个 Navigation 容器应复用同一个 NavPathStack,不要在每次 build 或点击时重新创建。每次重新创建会导致路由栈信息丢失,页面返回逻辑失效。

习题 2(单选题)

题目:以下哪个组件是 Navigation 子页面的根容器?

A. NavBar
B. NavPathStack
C. NavDestination
D. Navigation

答案:C

解读:NavDestination 是 Navigation 子页面的根容器,用于承载子页面的特殊属性和生命周期,可以配置独立的标题栏、菜单栏与工具栏等属性。NavBar 是导航栏(主页面),NavPathStack 是导航控制器,Navigation 是导航根视图容器。

习题 3(多选题)

题目:关于 SideBarContainer,以下说法正确的有(多选):

A. 必须且仅包含 2 个子组件,第一个是侧边栏,第二个是内容区
B. Embed 模式下侧边栏覆盖在内容区上方
C. Overlay 模式下侧边栏不影响内容区布局
D. 当容器尺寸小于 minContentWidth + minSideBarWidth 且未设置 showSideBar 时,侧边栏自动隐藏

答案:A、C、D

解读:SideBarContainer 必须且仅包含 2 个子组件,第一个表示侧边栏,第二个表示内容区,选项 A 正确。Embed 模式下侧边栏嵌入到组件内与内容区并列显示,Overlay 模式下侧边栏覆盖在内容区上方、不影响内容区布局,选项 B 描述相反,选项 C 正确。组件尺寸小于 minContentWidth + minSideBarWidth 且未设置 showSideBar 时侧边栏自动隐藏,选项 D 正确。

习题 4(代码填空题)

题目:请补全以下 Navigation 代码,实现点击按钮跳转到名称为 “detail” 的子页面。

Navigation(this.pageStack){Button('查看详情').onClick(()=>{// 在此处填写代码______________})}.navDestination(this.pageMap)

答案:this.pageStack.pushPathByName(‘detail’, null)

解读:pushPathByName 是 NavPathStack 的入栈方法,第一个参数是 NavDestination 的名称,第二个参数是传递的参数(无参数时可传 null)。

习题 5(代码改错题)

题目:以下 Tabs 代码存在布局问题,请指出问题并修正。

Tabs(){TabContent(){Text('内容1')}.tabBar('标签1')}.height('100%')

答案:代码缺少 .width(‘100%’) 属性。TabContent 组件不支持设置通用宽度属性,其宽度默认撑满 Tabs 父组件,但 Tabs 组件本身如果没有设置宽度,可能无法正确撑满页面。修正如下:

Tabs(){TabContent(){Text('内容1')}.tabBar('标签1')}.width('100%').height('100%')

解读:TabContent 的宽度默认撑满 Tabs 父组件,但 Tabs 组件需要显式设置宽度以确保布局正确。

习题 6(简答题)

题目:简述 Navigation 的单栏、分栏、自适应三种显示模式的区别及适用场景。

答案:单栏模式(Stack)在 Navigation 容器宽度小于 600vp 时建议使用,此模式下发生路由跳转时整个页面都会被替换,适合手机竖屏场景。分栏模式(Split)在容器宽度大于等于 600vp 时建议使用,Navigation 分为左右两部分,左侧为导航栏,右侧为子页面,路由跳转时只有右边子页会被替换,适合平板、PC 大屏场景。自适应模式(Auto)为默认值,会自动监听屏幕属性,折叠屏或平板时默认分栏显示,折叠状态或普通手机时可单栏显示,适合需要一次开发多端部署的应用。

解读:Navigation 通过 mode 属性控制显示模式,开发者可以将 mode 设置为 NavigationMode.Stack、NavigationMode.Split 或 NavigationMode.Auto,实现不同设备形态下的自适应布局。

习题 7(简答题)

题目:简述多页面应用中,Navigation、Tabs、SideBarContainer 三种组件的典型协作方式。

答案:在典型的多页面应用中,Navigation 作为应用根容器,管理全局页面栈和跨页面的路由跳转。Tabs 作为主框架页面(首页、发现、消息、我的)的组织方式,每个 Tab 内部可以再嵌套 Navigation 实现该 Tab 下的页面跳转。SideBarContainer 用于实现侧边菜单(如设置、帮助中心),在平板或 PC 大屏上以 Embed 模式并排显示,在手机上以 Overlay 模式覆盖显示。三种组件各司其职:Navigation 管路由,Tabs 管主框架,SideBarContainer 管侧边导航。

解读:三种组件的协作方式取决于应用的具体需求。Navigation 是路由的底座,Tabs 是主界面的骨架,SideBarContainer 是辅助导航的扩展。开发者应根据页面结构合理组合使用,避免过度嵌套导致的性能问题。

六、本节知识点总结

Navigation 完整架构
由 Navigation(根视图容器)、NavDestination(子页面容器)和 NavPathStack(导航控制器)三部分组成。NavPathStack 管理页面栈,支持 pushPathByName、pop、replacePath 等操作,整个 Navigation 容器应复用同一个 NavPathStack。

三种显示模式
单栏模式(Stack)适合手机竖屏,分栏模式(Split)适合平板大屏,自适应模式(Auto)根据屏幕宽度自动切换。通过 mode 属性控制。

Tabs 选项卡
由 TabContent(内容页)和 TabBar(导航栏)组成,支持底部、顶部、侧边三种导航位置。TabContent 宽度默认撑满 Tabs,高度由 Tabs 高度和 TabBar 高度决定。标准 Tabs 不支持在 tabBar 中添加其他组件,通过 barHeight(0) 隐藏原生 TabBar 可实现自定义导航栏。

Tabs 与滚动联动
API 13 起 bindTabsToScrollable() 可将 Tabs 与 Scroll/List/Grid 绑定,内容上滑自动隐藏 TabBar,下滑自动显示。

SideBarContainer
侧边栏容器,第一个子组件是侧边栏,第二个是内容区。Embed 模式并排显示适合大屏,Overlay 模式覆盖显示适合小屏。支持通过 showSideBar、sideBarWidth、minContentWidth 等属性控制显隐和尺寸。

多页面架构设计
Navigation 作为根容器管路由,Tabs 组织主框架页面,SideBarContainer 实现侧边导航。跨模块跳转使用 Router,单模块应用推荐全部使用 Navigation。

下节预告
第17课将进入 ArkUI 应用国际化与无障碍适配的学习,涵盖多语言资源管理、RTL 布局适配、无障碍属性配置以及多设备适配的核心方法。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/9 5:24:07

AI Agent_12 AI 向量数据库

下面先看两张机制图 ——RAG 里向量数据库的完整工作流,以及向量空间与近似索引(ANN)的内部机理—— 再逐节展开。一、先建立直觉:向量数据库是什么传统数据库(如 MySQL):存 "表格行"…

作者头像 李华
网站建设 2026/10/9 5:22:52

企业为什么要做绩效考核

绩效考核是指企业在既定的战略目标下,运用特定的标准和指标,对员工的工作行为及取得的工作业绩进行评估,并运用评估的结果对员工将来的工作行为和工作业绩产生正面引导的过程和方法。 现在大部分的企业都会花费大量的人力、物力、精力来搭建自…

作者头像 李华
网站建设 2026/10/9 5:17:08

Gazebo工业仿真场景搭建全攻略:从世界文件到机械臂与AGV联动

做机器人开发的人,几乎都绕不开一个问题:算法写好了,怎么安全、低成本地把流程跑通。直接在实体设备上调试不仅成本高,还有安全隐患,设备空转、现场风险、时间窗口,每一项都压得人喘不过气。所以基于Gazebo…

作者头像 李华