ArkTS 中 Tabs 组件总结
一、Tabs 组件概述
Tabs 组件是 ArkTS 中用于实现选项卡式导航的容器组件,通常与 TabContent 子组件配合使用,用于构建多页面切换的应用界面。
二、基本用法
2.1 基础语法
Tabs(value?: { barPosition?: BarPosition, index?: number, controller?: TabsController })
2.2 最简单的示例
@Entry
@***ponent
struct BasicTabsExample {
build() {
Tabs() {
TabContent() {
Text('首页内容')
}
.tabBar('首页')
TabContent() {
Text('消息内容')
}
.tabBar('消息')
TabContent() {
Text('我的内容')
}
.tabBar('我的')
}
}
}
三、构造参数 (TabsOptions)
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| barPosition | BarPosition | 否 | TabBar 的位置,默认为 BarPosition.Start |
| index | number | 否 | 初始选中的标签页索引,默认为 0 |
| controller | TabsController | 否 | Tabs 控制器,用于控制 Tabs 组件的切换 |
3.1 BarPosition 枚举
enum BarPosition {
Start, // TabBar 位于顶部或左侧(默认)
End, // TabBar 位于底部或右侧
}
四、常用属性
4.1 布局相关
vertical
设置 Tabs 是否为垂直布局
Tabs() {
// ...
}
.vertical(false) // false: 水平布局(默认), true: 垂直布局
barMode
设置 TabBar 的布局模式
Tabs() {
// ...
}
.barMode(BarMode.Fixed) // Fixed: 固定模式, Scrollable: 可滚动模式
BarMode 枚举:
-
BarMode.Fixed:所有标签均分 TabBar 宽度,不可滚动 -
BarMode.Scrollable:TabBar 可滚动,适合标签数量较多的场景
barWidth
设置 TabBar 的宽度
Tabs() {
// ...
}
.barWidth(200) // 数字或百分比
barHeight
设置 TabBar 的高度
Tabs() {
// ...
}
.barHeight(56) // 常用值: 56vp
4.2 样式相关
scrollable (已废弃,请使用 barMode)
是否可滚动
Tabs() {
// ...
}
.scrollable(true)
animationDuration
设置切换动画的持续时间(毫秒)
Tabs() {
// ...
}
.animationDuration(300) // 默认 300ms
barBackgroundColor
设置 TabBar 的背景颜色
Tabs() {
// ...
}
.barBackgroundColor('#F1F3F5')
4.3 交互相关
onChange
Tab 页签切换时触发的回调
Tabs() {
// ...
}
.onChange((index: number) => {
console.info('当前选中的 Tab 索引: ' + index)
})
onTabBarClick
点击 TabBar 时触发的回调
Tabs() {
// ...
}
.onTabBarClick((index: number) => {
console.info('点击了 Tab 索引: ' + index)
})
五、TabsController 控制器
TabsController 用于控制 Tabs 组件的页面切换。
5.1 方法
| 方法名 | 参数 | 说明 |
|---|---|---|
| changeIndex | index: number | 切换到指定索引的 Tab |
5.2 使用示例
@Entry
@***ponent
struct TabsControllerExample {
private controller: TabsController = new TabsController()
@State currentIndex: number = 0
build() {
Column() {
// 自定义按钮控制 Tab 切换
Row({ space: 10 }) {
Button('切换到首页')
.onClick(() => {
this.controller.changeIndex(0)
})
Button('切换到消息')
.onClick(() => {
this.controller.changeIndex(1)
})
}
.margin({ bottom: 20 })
Tabs({
controller: this.controller,
index: this.currentIndex
}) {
TabContent() {
Text('首页内容')
.fontSize(20)
}
.tabBar('首页')
TabContent() {
Text('消息内容')
.fontSize(20)
}
.tabBar('消息')
TabContent() {
Text('我的内容')
.fontSize(20)
}
.tabBar('我的')
}
.onChange((index: number) => {
this.currentIndex = index
})
}
.width('100%')
.height('100%')
.padding(20)
}
}
六、TabContent 组件
TabContent 是 Tabs 的子组件,用于定义每个标签页的内容。
6.1 tabBar 属性
tabBar 可以设置为字符串、CustomBuilder 或对象类型。
简单文本
TabContent() {
Text('内容')
}
.tabBar('标题')
完整对象配置
TabContent() {
Text('内容')
}
.tabBar({
icon: $r('app.media.home'),
selectedIcon: $r('app.media.home_selected'),
text: '首页'
})
自定义 TabBar
@Builder TabBarBuilder(title: string, icon: Resource, index: number) {
Column() {
Image(this.currentIndex === index ? this.selectedIcons[index] : icon)
.width(24)
.height(24)
Text(title)
.fontSize(12)
.fontColor(this.currentIndex === index ? '#007DFF' : '#999')
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
// 使用自定义 TabBar
TabContent() {
Text('首页内容')
}
.tabBar(this.TabBarBuilder('首页', $r('app.media.home'), 0))
七、实际应用场景
7.1 底部导航栏
@Entry
@***ponent
struct BottomNavigation {
@State currentIndex: number = 0
private tabsController: TabsController = new TabsController()
@Builder TabBuilder(title: string, targetIndex: number, icon: Resource, selectedIcon: Resource) {
Column() {
Image(this.currentIndex === targetIndex ? selectedIcon : icon)
.size({ width: 24, height: 24 })
Text(title)
.fontSize(10)
.fontColor(this.currentIndex === targetIndex ? '#007DFF' : '#999999')
.margin({ top: 4 })
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
.onClick(() => {
this.currentIndex = targetIndex
this.tabsController.changeIndex(targetIndex)
})
}
build() {
Tabs({
barPosition: BarPosition.End,
controller: this.tabsController,
index: this.currentIndex
}) {
TabContent() {
Column().width('100%').height('100%').backgroundColor('#00CB87')
}
.tabBar(this.TabBuilder('首页', 0, $r('app.media.home'), $r('app.media.home_selected')))
TabContent() {
Column().width('100%').height('100%').backgroundColor('#007DFF')
}
.tabBar(this.TabBuilder('消息', 1, $r('app.media.message'), $r('app.media.message_selected')))
TabContent() {
Column().width('100%').height('100%').backgroundColor('#FFBF00')
}
.tabBar(this.TabBuilder('我的', 2, $r('app.media.profile'), $r('app.media.profile_selected')))
}
.width('100%')
.height('100%')
.barHeight(56)
.barBackgroundColor(Color.White)
.animationDuration(300)
.onChange((index: number) => {
this.currentIndex = index
})
}
}
7.2 顶部选项卡(可滚动)
@Entry
@***ponent
struct ScrollableTopTabs {
@State currentIndex: number = 0
private categories: string[] = [
'推荐', '热点', '科技', '娱乐', '体育',
'财经', '军事', '汽车', '时尚', '游戏'
]
@Builder TabBarBuilder(title: string, index: number) {
Column() {
Text(title)
.fontSize(16)
.fontWeight(this.currentIndex === index ? FontWeight.Bold : FontWeight.Normal)
.fontColor(this.currentIndex === index ? '#007DFF' : '#333333')
.padding({ left: 16, right: 16 })
}
.height('100%')
.justifyContent(FlexAlign.Center)
}
build() {
Column() {
Tabs({ index: this.currentIndex }) {
ForEach(this.categories, (category: string, index: number) => {
TabContent() {
Column() {
Text(`${category} 内容区域`)
.fontSize(20)
.margin({ top: 50 })
}
.width('100%')
.height('100%')
.backgroundColor('#F5F5F5')
}
.tabBar(this.TabBarBuilder(category, index))
})
}
.width('100%')
.height('100%')
.barMode(BarMode.Scrollable)
.barHeight(44)
.barBackgroundColor(Color.White)
.animationDuration(200)
.onChange((index: number) => {
this.currentIndex = index
})
}
}
}
7.3 垂直选项卡
@Entry
@***ponent
struct VerticalTabsExample {
@State currentIndex: number = 0
build() {
Tabs({ index: this.currentIndex }) {
TabContent() {
Column() {
Text('分类1内容')
}
.width('100%')
.height('100%')
.backgroundColor('#FFE4E1')
}
.tabBar('分类1')
TabContent() {
Column() {
Text('分类2内容')
}
.width('100%')
.height('100%')
.backgroundColor('#E0FFFF')
}
.tabBar('分类2')
TabContent() {
Column() {
Text('分类3内容')
}
.width('100%')
.height('100%')
.backgroundColor('#F0FFF0')
}
.tabBar('分类3')
}
.width('100%')
.height('100%')
.vertical(true) // 设置为垂直布局
.barWidth(100) // TabBar 宽度
.barMode(BarMode.Fixed)
.onChange((index: number) => {
this.currentIndex = index
})
}
}
八、常用属性速查表
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| vertical | boolean | false | 是否为垂直布局 |
| barMode | BarMode | BarMode.Fixed | TabBar 布局模式 |
| barWidth | Length | - | TabBar 宽度 |
| barHeight | Length | - | TabBar 高度 |
| animationDuration | number | 300 | 切换动画时长(毫秒) |
| barBackgroundColor | ResourceColor | - | TabBar 背景颜色 |
| barPosition | BarPosition | BarPosition.Start | TabBar 位置 |
| index | number | 0 | 当前选中的标签页索引 |
| scrollable | boolean | false | 是否可滚动(已废弃) |
九、事件回调
| 事件名 | 参数类型 | 说明 |
|---|---|---|
| onChange | (index: number) | Tab 切换完成时触发 |
| onTabBarClick | (index: number) | 点击 TabBar 时触发 |
十、最佳实践建议
10.1 性能优化
- 使用
barMode替代废弃的scrollable属性 - 当标签数量较多时,使用
BarMode.Scrollable避免挤压 - 合理使用
animationDuration,不要设置过长的动画时长
10.2 用户体验
- 底部导航建议使用 3-5 个标签页
- 顶部选项卡适合内容分类较多的场景
- 提供清晰的选中状态视觉反馈
- 自定义 TabBar 时保持一致的尺寸和样式
10.3 布局建议
- 底部导航:
barPosition: BarPosition.End+barHeight: 56 - 顶部选项卡:
barPosition: BarPosition.Start+barHeight: 44-48 - 垂直侧边栏:
vertical: true+barWidth: 80-120
10.4 注意事项
- TabContent 必须作为 Tabs 的直接子组件
- index 值从 0 开始
- 使用 TabsController 时需要绑定 controller 参数
- 自定义 TabBar 需要使用 @Builder 装饰器
十一、总结
Tabs 组件是 HarmonyOS 应用开发中最常用的导航组件之一,通过合理配置属性和自定义 TabBar,可以实现多样化的导航效果。主要应用场景包括:
- 底部导航栏:适合主要功能模块切换
- 顶部选项卡:适合内容分类浏览
- 侧边导航:适合层级结构展示
掌握 Tabs 组件的使用,可以构建出用户体验良好的多页面应用。
参考文档:
- 华为开发者联盟 - Tabs 组件