鸿蒙学习实战之路:Tabs 组件开发场景最佳实践
Tabs 组件是 HarmonyOS 开发中常用的 UI 组件,用于实现页面内容的分类展示和快速切换。本文将结合华为开发者联盟的官方最佳实践,介绍 Tabs 组件的常见开发场景和实现方案。
关于本文
本文基于华为开发者联盟官方文档《Tabs 选项卡常见开发场景》整理而成,旨在帮助开发者快速掌握 Tabs 组件的最佳实践。
官方文档传送门永远是你的好伙伴,请收藏!
- 本文不能代替官方文档,所有内容均基于官方文档+个人实践经验总结
- 基本所有章节都会附上对应的文档链接,强烈建议你点击查看
- 所有代码示例建议自己动手尝试一下
- 如果英文水平不是很好,善用浏览器翻译功能
代码测试环境
确保你的开发环境符合以下要求:
| 软件/工具 | 版本要求 |
|---|---|
| HarmonyOS SDK | API Level 11 |
| TypeScript | 5.0+ |
| DevEco Studio | 4.1+ |
| 设备要求 | 支持 HarmonyOS NEXT 的真机或模拟器 |
Tabs 组件概述
Tabs 组件是一种常见的界面导航组件,用于将内容分类并允许用户在不同类别之间快速切换。在 HarmonyOS 中,Tabs 组件提供了丰富的配置选项和事件监听,支持自定义样式和交互效果。
Tabs 组件主要由以下部分组成:
- TabBar:选项卡导航栏,显示所有可切换的选项
- TabContent:内容区域,显示当前选中选项对应的内容
常见开发场景
1. 基础 Tabs 组件使用
功能说明:实现一个简单的 Tabs 组件,包含三个选项卡,分别显示不同的内容。
Tabs 导航样式:
常见的应用页签导航效果包括底部导航、顶部导航和侧边导航。

实现步骤:
- 导入 Tabs 组件
- 配置 TabBar 选项
- 设置 TabContent 内容
代码示例:
typescript
import { Tabs, TabBar, TabContent, Text } from '@kit.ArkUI'
@Entry
@Component
struct BasicTabsExample {
private controller: TabsController = new TabsController()
build() {
Column() {
Tabs({ controller: this.controller })
.barPosition(BarPosition.Start)
.width('100%')
.height(500)
.backgroundColor('#F5F5F5')
{
// TabBar选项配置
TabBar() {
Text('首页').width('100%')
Text('分类').width('100%')
Text('我的').width('100%')
}
.width('100%')
.height(60)
.backgroundColor('#FFFFFF')
// TabContent内容配置
TabContent() {
Column() {
Text('首页内容')
.fontSize(20)
.fontWeight(FontWeight.Bold)
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
TabContent() {
Column() {
Text('分类内容')
.fontSize(20)
.fontWeight(FontWeight.Bold)
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
TabContent() {
Column() {
Text('我的内容')
.fontSize(20)
.fontWeight(FontWeight.Bold)
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
}
}
.padding(10)
}
}
注意事项:
- 必须使用 TabsController 来控制 Tabs 组件的切换
- TabBar 和 TabContent 的数量必须保持一致
- 可以通过 barPosition 属性设置 TabBar 的位置(顶部或底部)
2. 自定义 Tabs 样式
功能说明:实现一个自定义样式的 Tabs 组件,包括自定义 TabBar 的颜色、字体和指示器样式。
自定义页签样式:
对于底部导航栏,通常用于应用主页面的功能区分。为了更好的用户体验,开发者通常会自定义页签样式,将页签自定义为图标加文字标题的形式,并且在选中和非选中的状态下提供不同的样式。

实现步骤:
- 配置 TabBar 的背景色和字体样式
- 自定义指示器的样式和位置
- 设置选中和未选中状态的样式
代码示例:
typescript
import { Tabs, TabBar, TabContent, Text } from '@kit.ArkUI'
@Entry
@Component
struct CustomStyleTabsExample {
private controller: TabsController = new TabsController()
build() {
Column() {
Tabs({ controller: this.controller })
.barPosition(BarPosition.Start)
.width('100%')
.height(500)
.backgroundColor('#F5F5F5')
// 自定义指示器样式
.indicatorStyle({
width: 20,
height: 3,
borderRadius: 1.5,
backgroundColor: '#007DFF'
})
{
TabBar() {
Text('首页')
.width('100%')
.fontSize(16)
.fontColor('#666666')
.fontWeight(FontWeight.Normal)
// 选中状态样式
.selectedFontColor('#007DFF')
.selectedFontSize(18)
.selectedFontWeight(FontWeight.Bold)
Text('分类')
.width('100%')
.fontSize(16)
.fontColor('#666666')
.fontWeight(FontWeight.Normal)
.selectedFontColor('#007DFF')
.selectedFontSize(18)
.selectedFontWeight(FontWeight.Bold)
Text('我的')
.width('100%')
.fontSize(16)
.fontColor('#666666')
.fontWeight(FontWeight.Normal)
.selectedFontColor('#007DFF')
.selectedFontSize(18)
.selectedFontWeight(FontWeight.Bold)
}
.width('100%')
.height(60)
.backgroundColor('#FFFFFF')
.borderBottomWidth(1)
.borderBottomColor('#EEEEEE')
// TabContent内容保持不变
TabContent() {
Column() {
Text('首页内容')
.fontSize(20)
.fontWeight(FontWeight.Bold)
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
TabContent() {
Column() {
Text('分类内容')
.fontSize(20)
.fontWeight(FontWeight.Bold)
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
TabContent() {
Column() {
Text('我的内容')
.fontSize(20)
.fontWeight(FontWeight.Bold)
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
}
}
.padding(10)
}
}
注意事项:
- 可以通过 indicatorStyle 属性自定义指示器的样式
- TabBar 的子组件可以设置选中和未选中状态的不同样式
- 建议保持样式的统一性和美观性
3. 数据加载与动态 Tabs
功能说明:实现一个动态加载数据的 Tabs 组件,根据服务器返回的数据动态生成选项卡和内容。
实现步骤:
- 定义数据模型
- 模拟数据加载
- 动态生成 TabBar 和 TabContent
代码示例:
typescript
import { Tabs, TabBar, TabContent, Text, List, ListItem, LoadingProgress } from '@kit.ArkUI'
// 定义数据模型
interface TabItem {
id: string
title: string
content: string[]
}
@Entry
@Component
struct DynamicTabsExample {
private controller: TabsController = new TabsController()
@State tabList: TabItem[] = []
@State isLoading: boolean = true
// 模拟数据加载
async aboutToAppear() {
this.isLoading = true
// 模拟网络请求延迟
await new Promise(resolve => setTimeout(resolve, 1000))
// 模拟服务器返回的数据
this.tabList = [
{
id: '1',
title: '推荐',
content: ['推荐内容1', '推荐内容2', '推荐内容3', '推荐内容4', '推荐内容5']
},
{
id: '2',
title: '热点',
content: ['热点内容1', '热点内容2', '热点内容3', '热点内容4', '热点内容5']
},
{
id: '3',
title: '科技',
content: ['科技内容1', '科技内容2', '科技内容3', '科技内容4', '科技内容5']
},
{
id: '4',
title: '娱乐',
content: ['娱乐内容1', '娱乐内容2', '娱乐内容3', '娱乐内容4', '娱乐内容5']
}
]
this.isLoading = false
}
build() {
Column() {
if (this.isLoading) {
// 加载状态
Column() {
LoadingProgress()
.color('#007DFF')
.height(40)
.width(40)
Text('加载中...')
.fontSize(14)
.fontColor('#666666')
.margin({ top: 10 })
}
.width('100%')
.height(500)
.justifyContent(FlexAlign.Center)
} else {
// 数据加载完成,显示Tabs组件
Tabs({ controller: this.controller })
.barPosition(BarPosition.Start)
.width('100%')
.height(500)
.backgroundColor('#F5F5F5')
{
// 动态生成TabBar
TabBar() {
ForEach(this.tabList, (item: TabItem) => {
Text(item.title)
.width('100%')
.fontSize(16)
.fontColor('#666666')
.selectedFontColor('#007DFF')
}, (item: TabItem) => item.id)
}
.width('100%')
.height(60)
.backgroundColor('#FFFFFF')
// 动态生成TabContent
ForEach(this.tabList, (item: TabItem) => {
TabContent() {
List() {
ForEach(item.content, (content: string, index: number) => {
ListItem() {
Text(content)
.width('100%')
.padding(20)
.fontSize(16)
.borderBottomWidth(1)
.borderBottomColor('#EEEEEE')
}
})
}
.width('100%')
.height('100%')
}
}, (item: TabItem) => item.id)
}
}
}
.padding(10)
}
}
注意事项:
- 使用 ForEach 动态生成 TabBar 和 TabContent 时,必须提供唯一的 key 值
- 数据加载过程中应显示加载状态,提升用户体验
- 可以根据实际需求调整数据加载策略(如懒加载)
4. 多层嵌套 Tabs
功能说明:实现多层嵌套的 Tabs 组件,常用于复杂页面的内容分类展示。
嵌套 Tabs 效果:
多层嵌套 Tabs 组件可以实现复杂的内容分类展示,常见于电商应用的商品分类和品牌馆等场景。

实现步骤:
- 创建外层 Tabs 组件
- 在内层 TabContent 中创建内层 Tabs 组件
- 配置内外层 Tabs 的样式和交互
代码示例:
typescript
import { Tabs, TabBar, TabContent, Text } from '@kit.ArkUI'
@Entry
@Component
struct NestedTabsExample {
private outerController: TabsController = new TabsController()
private innerController1: TabsController = new TabsController()
private innerController2: TabsController = new TabsController()
build() {
Column() {
Text('外层Tabs')
.fontSize(20)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 10 })
// 外层Tabs
Tabs({ controller: this.outerController })
.barPosition(BarPosition.Start)
.width('100%')
.height(500)
.backgroundColor('#F5F5F5')
{
TabBar() {
Text('商品分类')
.width('100%')
.fontSize(16)
.selectedFontColor('#007DFF')
Text('品牌馆')
.width('100%')
.fontSize(16)
.selectedFontColor('#007DFF')
}
.width('100%')
.height(50)
.backgroundColor('#FFFFFF')
// 内层Tabs 1
TabContent() {
Column() {
Text('内层Tabs - 商品分类')
.fontSize(16)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 10 })
Tabs({ controller: this.innerController1 })
.barPosition(BarPosition.Start)
.width('100%')
.height('100%')
.backgroundColor('#FFFFFF')
.barMode(BarMode.Scrollable)
{
TabBar() {
ForEach(['手机', '电脑', '平板', '耳机', '手表', '配件'], (item: string) => {
Text(item)
.width(80)
.fontSize(14)
.selectedFontColor('#007DFF')
})
}
.width('100%')
.height(40)
.backgroundColor('#F5F5F5')
ForEach(['手机内容', '电脑内容', '平板内容', '耳机内容', '手表内容', '配件内容'], (item: string) => {
TabContent() {
Text(item)
.width('100%')
.height('100%')
.textAlign(TextAlign.Center)
.padding(20)
}
})
}
}
.width('100%')
.height('100%')
.padding(10)
}
// 内层Tabs 2
TabContent() {
Column() {
Text('内层Tabs - 品牌馆')
.fontSize(16)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 10 })
Tabs({ controller: this.innerController2 })
.barPosition(BarPosition.Start)
.width('100%')
.height('100%')
.backgroundColor('#FFFFFF')
.barMode(BarMode.Scrollable)
{
TabBar() {
ForEach(['华为', '荣耀', '小米', '苹果', '三星', 'OPPO', 'vivo'], (item: string) => {
Text(item)
.width(80)
.fontSize(14)
.selectedFontColor('#007DFF')
})
}
.width('100%')
.height(40)
.backgroundColor('#F5F5F5')
ForEach(['华为内容', '荣耀内容', '小米内容', '苹果内容', '三星内容', 'OPPO内容', 'vivo内容'], (item: string) => {
TabContent() {
Text(item)
.width('100%')
.height('100%')
.textAlign(TextAlign.Center)
.padding(20)
}
})
}
}
.width('100%')
.height('100%')
.padding(10)
}
}
}
.padding(10)
}
}
注意事项:
- 多层嵌套 Tabs 需要为每个 Tabs 组件创建独立的 TabsController
- 内层 Tabs 建议使用 BarMode.Scrollable 模式,避免选项过多导致显示不全
- 注意控制嵌套层级,避免过度嵌套影响性能和用户体验
常见问题与解决方案
1. Tabs 内容切换时数据丢失
问题描述:切换 Tabs 选项卡后,返回原选项卡时数据重新加载或丢失。
解决方案:
- 使用@State 装饰器保存状态数据
- 避免在 TabContent 中直接使用异步加载数据的逻辑
- 可以考虑使用缓存机制保存已加载的数据
2. Tabs 切换时动画不流畅
问题描述:Tabs 切换时出现卡顿或动画不流畅的情况。
解决方案:
- 优化 TabContent 中的组件渲染逻辑,避免过多的嵌套组件
- 对于复杂内容,考虑使用懒加载或虚拟列表
- 避免在切换时执行大量计算或网络请求
3. TabBar 选项过多显示不全
问题描述:TabBar 中的选项过多,导致部分选项无法显示。
解决方案:
- 设置 Tabs 的 barMode 为 BarMode.Scrollable,使 TabBar 可以横向滚动
- 考虑使用分段器或下拉菜单替代部分选项
- 优化选项卡的命名,使用更简洁的标题
参考文档
总结
Tabs 组件是 HarmonyOS 开发中非常实用的 UI 组件,通过本文的介绍,相信你已经掌握了 Tabs 组件的常见开发场景和最佳实践。在实际开发中,建议结合官方文档和项目需求,灵活运用 Tabs 组件,为用户提供更好的界面体验。
记住:
- 官方文档永远是你最好的学习资源
- 多动手实践才能真正掌握组件的使用
- 关注性能和用户体验,避免过度设计
祝你在鸿蒙开发之路上越走越远!🚀