HarmonyOS7 底部导航栏:Tabs 组件 5 分钟搞定多页签切换

发布时间:2026/7/24 20:58:24
HarmonyOS7 底部导航栏:Tabs 组件 5 分钟搞定多页签切换 文章目录前言Tabs 组件能干什么基础 Tab 布局自定义 TabBar 样式Tab 内容懒加载与 Navigation 联动写在最后前言做 App 首页十有八九要用到底部导航栏。我之前用自己写的方式实现代码一堆切换动画还卡。后来发现 HarmonyOS7 的 Tabs 组件5 分钟就能搞定而且自带丝滑切换。这篇聊聊 Tabs 组件怎么用从基础布局到自定义 TabBar再到懒加载和 Navigation 联动一次讲清楚。说实话我一开始没把 Tabs 当回事。觉得不就是个底部导航嘛自己画几个图标不就完了结果自己写了一版切换的时候白屏闪烁状态还各种丢。痛定思痛老老实实用 Tabs才发现真香——系统组件帮你想到了很多东西。Tabs 组件能干什么简单说Tabs 就是一个页签容器每个页签TabContent对应一个内容区点击页签切换内容。它能做的事底部导航栏微信那种底部 4 个 Tab点击切换页面顶部标签页今日头条那种频道切换侧边导航设置页面的分类导航自带滑动切换手指左右滑动就能切页预加载支持可以提前加载相邻页签切过去不卡划重点Tabs 的子组件只能是 TabContent而 TabContent 的直接子组件只能有一个。需要多个组件就套一个 Column 或 Row。基础 Tab 布局最简单的 Tabs3 行代码搞定Tabs(){TabContent(){Text(首页内容)}.tabBar(首页)TabContent(){Text(消息内容)}.tabBar(消息)TabContent(){Text(我的内容)}.tabBar(我的)}.barPosition(BarPosition.End)逐行讲解Tabs()是容器里面放TabContent子组件每个TabContent()包裹当前页签的内容.tabBar(首页)设置页签栏显示的文字.barPosition(BarPosition.End)把导航栏放底部默认是在顶部的就这样一个能滑动能点击的底部导航就出来了。不过默认样式比较素实际开发肯定要自定义。自定义 TabBar 样式默认的纯文字 TabBar 太丑了加上图标和选中态才像样。这就需要自定义 TabBarEntryComponentstruct MainPage{StatecurrentIndex:number0privatetabsController:TabsControllernewTabsController()BuildertabItemBuilder(icon:Resource,text:string,index:number){Column(){Image(this.currentIndexindex?icon:$r(app.media.ic_default)).width(24).height(24).fillColor(this.currentIndexindex?#007DFF:#999999)Text(text).fontSize(10).fontColor(this.currentIndexindex?#007DFF:#999999).margin({top:2})}.width(100%).height(100%).justifyContent(FlexAlign.Center)}build(){Column(){Tabs({controller:this.tabsController,index:this.currentIndex}){TabContent(){Text(首页内容区)}.tabBar(this.tabItemBuilder($r(app.media.ic_home_selected),首页,0))TabContent(){Text(消息内容区)}.tabBar(this.tabItemBuilder($r(app.media.ic_msg_selected),消息,1))TabContent(){Text(我的内容区)}.tabBar(this.tabItemBuilder($r(app.media.ic_mine_selected),我的,2))}.barPosition(BarPosition.End).onChange((index:number){this.currentIndexindex})}.width(100%).height(100%)}}关键代码讲解State currentIndex跟踪当前选中页签必须用 State否则切换不刷新 UITabsController控制器可以代码跳转页签比如this.tabsController.changeIndex(2)Builder tabItemBuilder是自定义 TabBar 的核心——根据currentIndex判断选中态切换图标和颜色.onChange()监听页签切换更新currentIndexicon: Resource参数类型用Resource这样能用$r()引用资源小技巧选中图标和未选中图标用同一个资源通过.fillColor()改颜色就行省得切两套图。Tab 内容懒加载Tabs 默认会把所有 TabContent 一口气加载。3 个 Tab 还好要是 5 个 6 个每个里面还请求数据启动就卡成狗。HarmonyOS7 提供了preloadItems方法可以按需预加载.onAppear((){try{this.tabsController.preloadItems([1])}catch(e){console.error(预加载失败: e)}}).onChange((index:number){this.currentIndexindexletpreloadList:number[][]if(index0){preloadList.push(index-1)}if(index4){preloadList.push(index1)}try{this.tabsController.preloadItems(preloadList)}catch(e){console.error(预加载失败: e)}})逻辑说明onAppear里预加载第 2 个页签用户大概率会切过去onChange里预加载当前页签的前后各一页preloadItems必须在 Tabs 和 Controller 绑定之后调用放aboutToAppear里会不生效务必try-catchController 没绑定时会抛异常说白了就是不提前全加载切到哪个附近就预加载哪个。用户体验不差性能还好。与 Navigation 联动实际项目中Tabs 通常嵌在 Navigation 的首页里子页面用 NavDestination 跳转。这是最经典的组合EntryComponentstruct IndexPage{ProvidenavPathStack:NavPathStacknewNavPathStack()StatecurrentIndex:number0build(){Navigation(this.navPathStack){Tabs({index:this.currentIndex}){TabContent(){HomePage()}.tabBar(首页)TabContent(){MessagePage()}.tabBar(消息)TabContent(){MinePage()}.tabBar(我的)}.barPosition(BarPosition.End).onChange((index:number){this.currentIndexindex})}.navDestination(this.pageMap).hideTitleBar(true)}BuilderpageMap(name:string){if(nameDetailPage){DetailPage()}elseif(nameSettingsPage){SettingsPage()}}}要点Navigation包在最外层Tabs 作为首页内容Provide navPathStack通过Consume在子页面里就能拿到不用层层传参子页面跳转用this.navPathStack.pushPathByName(DetailPage, null)navDestination做路由映射名字对应组件这种结构的好处是Tab 页签内的页面跳转和 Tab 切换互不干扰各管各的。写在最后Tabs 组件说简单也简单3 行代码能跑说复杂也复杂自定义样式、懒加载、Navigation 联动都要考虑。我的建议是先用最简版跑起来再逐步加自定义和优化。别一上来就搞复杂的自定义 TabBar容易把自己绕进去。