首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >HarmonyOS应用开发实战 | ArkTS Tabs页签组件使用指南

HarmonyOS应用开发实战 | ArkTS Tabs页签组件使用指南

作者头像
红目香薰
发布2025-12-16 15:44:56
发布2025-12-16 15:44:56
1160
举报
文章被收录于专栏:CSDNToQQCodeCSDNToQQCode

💫 坚果派·红目香薰 倾情分享

🎯 用心打造每一个技术细节,为开发者创造更多价值

📱 让HarmonyOS开发变得更简单、更有趣


✨ 写在前面的话

嗨,亲爱的技术朋友们!👋

我是来自坚果派的红目香薰,一个热爱技术、专注HarmonyOS开发的程序媛。在这个数字化飞速发展的时代,HarmonyOS作为华为自主研发的操作系统,正在改变着我们的数字生活体验。

🌈 为什么要写这个系列?

  • 💡 让复杂的技术变得简单易懂
  • 🚀 帮助更多开发者快速上手HarmonyOS
  • 💝 分享实战经验,避免踩坑
  • 🌟 用代码创造美好,用技术传递温暖

每一个Demo都是我精心设计和反复测试的结果,希望能够为你的HarmonyOS开发之路点亮一盏明灯。✨

今天我们来深入学习HarmonyOS中最常用的导航组件之一——Tabs页签组件。从基础页签到炫酷的自定义样式,让我们一起打造优雅的页签导航体验!


📋 Demo功能说明

🎯 核心功能

本Demo展示了HarmonyOS中Tabs组件的全面使用方法,包括:

  • 📑 基础页签布局和切换功能
  • 🎨 自定义页签样式和图标
  • 📱 垂直和水平页签方向
  • 💫 页签切换动画和过渡效果
  • 🎯 页签事件监听和处理
  • 🔄 动态添加和删除页签
  • ✨ 页签指示器和徽章显示
  • 🌟 实用的页签应用场景
✨ 特色亮点
  • 🎨 视觉精美:多种页签样式和动画效果
  • 🚀 交互流畅:丝滑的页签切换体验
  • 📱 响应式设计:适配不同屏幕尺寸和方向
  • 💡 功能丰富:支持图标、徽章、自定义内容
  • 🌟 实用性强:涵盖常见的页签使用场景
🎨 界面展示

界面采用多样化的页签展示:

  • 经典页签:底部导航栏样式
  • 顶部页签:新闻应用风格的页签
  • 垂直页签:侧边栏导航样式
  • 自定义页签:个性化图标和样式
  • 动态页签:可添加删除的页签
📱 适用场景
  • 📱 应用主界面的底部导航栏
  • 📰 新闻应用的分类页签
  • 🛍️ 电商应用的商品分类页签
  • ⚙️ 设置页面的功能分组页签
  • 📊 数据展示的多维度切换页签
  • 🎮 游戏应用的功能模块页签

🔧 核心代码说明

📁 项目结构
代码语言:javascript
复制
TabsDemo/

├── src/

│   ├── main/

│   │   ├── ets/

│   │   │   ├── pages/

│   │   │   │   └── Index.ets          // 主页面

│   │   │   └── entryability/

│   │   └── resources/

│   │       ├── base/

│   │       │   ├── element/

│   │       │   └── media/

│   │       └── rawfile/

│   └── module.json5
🎯 关键技术点
1. Tabs组件基础结构
代码语言:javascript
复制
Tabs({ barPosition: BarPosition.End }) {

  TabContent() {

    // 页签内容

  }

  .tabBar('首页')



  TabContent() {

    // 页签内容

  }

  .tabBar('发现')

}

.width('100%')

.height('100%')
2. 自定义页签样式
代码语言:javascript
复制
TabContent() {

  // 内容

}

.tabBar(this.TabBuilder(0, '首页', '🏠'))
3. 页签控制属性
  • barPosition: 页签栏位置(顶部/底部)
  • vertical: 垂直/水平布局
  • scrollable: 页签是否可滚动
  • barMode: 页签栏模式
4. 页签事件处理
  • onChange: 页签切换时触发
  • onTabBarClick: 页签点击时触发
💡 技术要点解析

自定义TabBar

使用@Builder装饰器创建自定义页签样式,支持图标、文字、徽章等元素。

页签切换动画

通过animationDuration属性控制切换动画时长和效果。

响应式布局

根据屏幕尺寸自动调整页签布局和样式。


📝 完整Demo代码

🏠 主页面代码
代码语言:javascript
复制
interface TabItemData {
  id: number
  title: string
  icon: string
  badge?: number
  content: string
}

interface NewsItemData {
  id: number
  title: string
  summary: string
  time: string
  category: string
}

@Entry
@Component
struct TabsDemo {
  @State currentIndex: number = 0
  @State selectedDemo: number = 0
  @State tabItems: TabItemData[] = []

  private bottomTabs: TabItemData[] = [
    { id: 1, title: '首页', icon: '🏠', content: '欢迎来到首页,这里展示最新的内容和推荐信息。' },
    { id: 2, title: '发现', icon: '🔍', badge: 3, content: '发现更多精彩内容,探索新的世界。' },
    { id: 3, title: '消息', icon: '💬', badge: 12, content: '查看最新消息和通知。' },
    { id: 4, title: '我的', icon: '👤', content: '个人中心,管理您的账户和设置。' }
  ]

  private topTabs: TabItemData[] = [
    { id: 1, title: '推荐', icon: '⭐', content: '为您精选的优质内容' },
    { id: 2, title: '科技', icon: '💻', content: '最新科技资讯和趋势' },
    { id: 3, title: '娱乐', icon: '🎬', content: '娱乐八卦和明星动态' },
    { id: 4, title: '体育', icon: '⚽', content: '体育赛事和运动资讯' },
    { id: 5, title: '财经', icon: '💰', content: '财经新闻和市场分析' }
  ]

  private newsData: NewsItemData[] = [
    { id: 1, title: 'HarmonyOS 4.0正式发布', summary: '华为发布全新操作系统,带来更多创新功能', time: '2小时前', category: '科技' },
    { id: 2, title: '人工智能技术新突破', summary: 'AI技术在各个领域取得重大进展', time: '4小时前', category: '科技' },
    { id: 3, title: '新电影票房创纪录', summary: '暑期档电影市场表现亮眼', time: '6小时前', category: '娱乐' },
    { id: 4, title: '奥运会精彩瞬间回顾', summary: '运动员们的精彩表现令人难忘', time: '8小时前', category: '体育' }
  ]

  aboutToAppear() {
    this.tabItems = [...this.bottomTabs]
  }

  build() {
    Column() {
      this.buildTitleSection()
      this.buildDemoSelector()
      if (this.selectedDemo === 0) {
        this.buildBottomTabs()
      } else if (this.selectedDemo === 1) {
        this.buildTopTabs()
      } else if (this.selectedDemo === 2) {
        this.buildVerticalTabs()
      } else {
        this.buildCustomTabs()
      }
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F5F5F5')
  }

  @Builder
  buildTitleSection() {
    Column({ space: 10 }) {
      Text('📑 HarmonyOS Tabs页签组件')
        .fontSize(24)
        .fontWeight(FontWeight.Bold)
        .fontColor(Color.White)
        .textAlign(TextAlign.Center)
        .width('100%')
        .padding(20)
        .borderRadius(15)
        .linearGradient({
          angle: 45,
          colors: [['#667eea', 0.0], ['#764ba2', 1.0]]
        })
        .shadow({
          radius: 10,
          color: '#40000000',
          offsetX: 0,
          offsetY: 5
        })
      Text('打造优雅的页签导航体验')
        .fontSize(14)
        .fontColor('#666666')
        .textAlign(TextAlign.Center)
        .fontStyle(FontStyle.Italic)
    }
    .width('100%')
    .backgroundColor(Color.White)
    .padding(20)
    .borderRadius(12)
    .margin({ bottom: 10 })
    .shadow({
      radius: 8,
      color: '#20000000',
      offsetX: 0,
      offsetY: 2
    })
  }

  @Builder
  buildDemoSelector() {
    Row({ space: 5 }) {
      Button('底部页签')
        .width(70)
        .height(35)
        .fontSize(12)
        .backgroundColor(this.selectedDemo === 0 ? '#3498DB' : '#ECF0F1')
        .fontColor(this.selectedDemo === 0 ? Color.White : '#7F8C8D')
        .borderRadius(8)
        .onClick(() => {
          this.selectedDemo = 0
        })
      Button('顶部页签')
        .width(70)
        .height(35)
        .fontSize(12)
        .backgroundColor(this.selectedDemo === 1 ? '#3498DB' : '#ECF0F1')
        .fontColor(this.selectedDemo === 1 ? Color.White : '#7F8C8D')
        .borderRadius(8)
        .onClick(() => {
          this.selectedDemo = 1
        })
      Button('垂直页签')
        .width(70)
        .height(35)
        .fontSize(12)
        .backgroundColor(this.selectedDemo === 2 ? '#3498DB' : '#ECF0F1')
        .fontColor(this.selectedDemo === 2 ? Color.White : '#7F8C8D')
        .borderRadius(8)
        .onClick(() => {
          this.selectedDemo = 2
        })
      Button('自定义')
        .width(70)
        .height(35)
        .fontSize(12)
        .backgroundColor(this.selectedDemo === 3 ? '#3498DB' : '#ECF0F1')
        .fontColor(this.selectedDemo === 3 ? Color.White : '#7F8C8D')
        .borderRadius(8)
        .onClick(() => {
          this.selectedDemo = 3
        })
    }
    .width('100%')
    .justifyContent(FlexAlign.SpaceEvenly)
    .padding({ left: 20, right: 20, bottom: 10 })
  }

  @Builder
  buildBottomTabs() {
    Tabs({ barPosition: BarPosition.End }) {
      ForEach(this.bottomTabs, (item: TabItemData, index: number) => {
        TabContent() {
          this.buildTabContentPage(item, index)
        }
        .tabBar(this.BottomTabBuilder(index, item.title, item.icon, item.badge))
      })
    }
    .width('100%')
    .layoutWeight(1)
    .barBackgroundColor('#FFFFFF')
    .barHeight(80)
    .animationDuration(300)
    .onChange((index: number) => {
      this.currentIndex = index
    })
  }

  @Builder
  buildTopTabs() {
    Tabs({ barPosition: BarPosition.Start }) {
      ForEach(this.topTabs, (item: TabItemData, index: number) => {
        TabContent() {
          this.buildNewsContentPage(item, index)
        }
        .tabBar(this.TopTabBuilder(index, item.title))
      })
    }
    .width('100%')
    .layoutWeight(1)
    .barBackgroundColor('#FFFFFF')
    .barHeight(50)
    .scrollable(true)
    .animationDuration(200)
    .onChange((index: number) => {
      this.currentIndex = index
    })
  }

  @Builder
  buildVerticalTabs() {
    Tabs({ barPosition: BarPosition.Start }) {
      TabContent() {
        this.buildSettingsPage('账户设置', '管理您的账户信息和安全设置')
      }
      .tabBar(this.VerticalTabBuilder(0, '账户设置', '👤'))
      TabContent() {
        this.buildSettingsPage('隐私设置', '控制您的隐私和数据使用权限')
      }
      .tabBar(this.VerticalTabBuilder(1, '隐私设置', '🔒'))
      TabContent() {
        this.buildSettingsPage('通知设置', '管理应用通知和提醒设置')
      }
      .tabBar(this.VerticalTabBuilder(2, '通知设置', '🔔'))
      TabContent() {
        this.buildSettingsPage('显示设置', '调整界面显示和主题设置')
      }
      .tabBar(this.VerticalTabBuilder(3, '显示设置', '🎨'))
      TabContent() {
        this.buildSettingsPage('关于应用', '查看应用版本和相关信息')
      }
      .tabBar(this.VerticalTabBuilder(4, '关于应用', 'ℹ️'))
    }
    .width('100%')
    .layoutWeight(1)
    .vertical(true)
    .barWidth(120)
    .barBackgroundColor('#F8F9FA')
    .animationDuration(250)
    .onChange((index: number) => {
      this.currentIndex = index
    })
  }

  @Builder
  buildCustomTabs() {
    Column({ space: 20 }) {
      Column({ space: 15 }) {
        Text('🎴 卡片式页签')
          .fontSize(18)
          .fontWeight(FontWeight.Medium)
          .fontColor('#333333')
          .alignSelf(ItemAlign.Start)
        Tabs({ barPosition: BarPosition.Start }) {
          TabContent() {
            this.buildCardContent('数据概览', '📊', '#3498DB')
          }
          .tabBar(this.CardTabBuilder(0, '概览', '📊', '#3498DB'))
          TabContent() {
            this.buildCardContent('用户分析', '👥', '#E74C3C')
          }
          .tabBar(this.CardTabBuilder(1, '用户', '👥', '#E74C3C'))
          TabContent() {
            this.buildCardContent('销售报表', '💰', '#27AE60')
          }
          .tabBar(this.CardTabBuilder(2, '销售', '💰', '#27AE60'))
          TabContent() {
            this.buildCardContent('系统设置', '⚙️', '#9B59B6')
          }
          .tabBar(this.CardTabBuilder(3, '设置', '⚙️', '#9B59B6'))
        }
        .width('100%')
        .height(300)
        .barBackgroundColor('transparent')
        .barHeight(60)
        .animationDuration(300)
      }
      .width('100%')
      .backgroundColor(Color.White)
      .padding(20)
      .borderRadius(12)
      .shadow({
        radius: 8,
        color: '#20000000',
        offsetX: 0,
        offsetY: 2
      })
      Column({ space: 15 }) {
        Row() {
          Text('🔄 动态页签')
            .fontSize(18)
            .fontWeight(FontWeight.Medium)
            .fontColor('#333333')
            .layoutWeight(1)
          Button('➕ 添加')
            .height(32)
            .fontSize(12)
            .backgroundColor('#27AE60')
            .borderRadius(16)
            .onClick(() => {
              this.addTab()
            })
        }
        .width('100%')
        Tabs({ barPosition: BarPosition.Start }) {
          ForEach(this.tabItems, (item: TabItemData, index: number) => {
            TabContent() {
              this.buildDynamicTabContent(item, index)
            }
            .tabBar(this.DynamicTabBuilder(index, item.title, item.icon))
          })
        }
        .width('100%')
        .height(250)
        .barBackgroundColor('#F8F9FA')
        .barHeight(50)
        .scrollable(true)
        .animationDuration(200)
      }
      .width('100%')
      .backgroundColor(Color.White)
      .padding(20)
      .borderRadius(12)
      .shadow({
        radius: 8,
        color: '#20000000',
        offsetX: 0,
        offsetY: 2
      })
    }
    .layoutWeight(1)
    .padding({ left: 20, right: 20 })
  }

  @Builder
  BottomTabBuilder(index: number, title: string, icon: string, badge?: number) {
    Column({ space: 5 }) {
      Stack({ alignContent: Alignment.TopEnd }) {
        Text(icon)
          .fontSize(24)
          .fontColor(this.currentIndex === index ? '#3498DB' : '#999999')
        if (badge && badge > 0) {
          Text(badge > 99 ? '99+' : badge.toString())
            .fontSize(10)
            .fontColor(Color.White)
            .backgroundColor('#E74C3C')
            .borderRadius(8)
            .padding({ left: 4, right: 4, top: 1, bottom: 1 })
            .margin({ top: -5, right: -5 })
        }
      }
      Text(title)
        .fontSize(12)
        .fontColor(this.currentIndex === index ? '#3498DB' : '#999999')
        .fontWeight(this.currentIndex === index ? FontWeight.Medium : FontWeight.Normal)
    }
    .width(60)
    .height(60)
    .justifyContent(FlexAlign.Center)
  }

  @Builder
  TopTabBuilder(index: number, title: string) {
    Column({ space: 5 }) {
      Text(title)
        .fontSize(16)
        .fontColor(this.currentIndex === index ? '#3498DB' : '#666666')
        .fontWeight(this.currentIndex === index ? FontWeight.Bold : FontWeight.Normal)
        .padding({ left: 15, right: 15 })
      if (this.currentIndex === index) {
        Divider()
          .width(30)
          .height(3)
          .color('#3498DB')
          .borderRadius(2)
      }
    }
    .height(50)
    .justifyContent(FlexAlign.Center)
  }

  @Builder
  VerticalTabBuilder(index: number, title: string, icon: string) {
    Row({ space: 10 }) {
      Text(icon)
        .fontSize(20)
        .fontColor(this.currentIndex === index ? '#3498DB' : '#666666')
      Text(title)
        .fontSize(14)
        .fontColor(this.currentIndex === index ? '#3498DB' : '#666666')
        .fontWeight(this.currentIndex === index ? FontWeight.Medium : FontWeight.Normal)
        .layoutWeight(1)
    }
    .width('100%')
    .height(50)
    .padding({ left: 15, right: 15 })
    .backgroundColor(this.currentIndex === index ? '#E3F2FD' : 'transparent')
    .borderRadius(8)
    .justifyContent(FlexAlign.Start)
  }

  @Builder
  CardTabBuilder(index: number, title: string, icon: string, color: string) {
    Column({ space: 8 }) {
      Text(icon)
        .fontSize(20)
        .fontColor(this.currentIndex === index ? Color.White : color)
      Text(title)
        .fontSize(12)
        .fontColor(this.currentIndex === index ? Color.White : color)
        .fontWeight(FontWeight.Medium)
    }
    .width(80)
    .height(50)
    .backgroundColor(this.currentIndex === index ? color : '#F8F9FA')
    .borderRadius(12)
    .justifyContent(FlexAlign.Center)
    .shadow(this.currentIndex === index ? {
      radius: 8,
      color: color + '40',
      offsetX: 0,
      offsetY: 4
    } : undefined)
  }

  @Builder
  DynamicTabBuilder(index: number, title: string, icon: string) {
    Row({ space: 8 }) {
      Text(icon)
        .fontSize(16)
      Text(title)
        .fontSize(14)
        .fontColor(this.currentIndex === index ? '#3498DB' : '#666666')
        .fontWeight(this.currentIndex === index ? FontWeight.Medium : FontWeight.Normal)
      if (this.tabItems.length > 1) {
        Text('✕')
          .fontSize(12)
          .fontColor('#999999')
          .onClick(() => {
            this.removeTab(index)
          })
      }
    }
    .padding({ left: 12, right: 8, top: 8, bottom: 8 })
    .backgroundColor(this.currentIndex === index ? '#E3F2FD' : 'transparent')
    .borderRadius(20)
  }

  @Builder
  buildTabContentPage(item: TabItemData, index: number) {
    Column({ space: 30 }) {
      Column({ space: 15 }) {
        Text(item.icon)
          .fontSize(64)
        Text(item.title)
          .fontSize(28)
          .fontWeight(FontWeight.Bold)
          .fontColor('#333333')
        Text(item.content)
          .fontSize(16)
          .fontColor('#666666')
          .textAlign(TextAlign.Center)
          .lineHeight(24)
      }
      Column({ space: 15 }) {
        Text('✨ 主要功能')
          .fontSize(18)
          .fontWeight(FontWeight.Medium)
          .fontColor('#333333')
          .alignSelf(ItemAlign.Start)
        Grid() {
          GridItem() {
            this.buildFeatureCard('📊', '数据统计', '查看详细数据')
          }
          GridItem() {
            this.buildFeatureCard('🔔', '消息通知', '管理通知设置')
          }
          GridItem() {
            this.buildFeatureCard('⚙️', '系统设置', '个性化配置')
          }
          GridItem() {
            this.buildFeatureCard('❓', '帮助中心', '获取使用帮助')
          }
        }
        .columnsTemplate('1fr 1fr')
        .rowsTemplate('1fr 1fr')
        .columnsGap(15)
        .rowsGap(15)
        .width('100%')
        .height(200)
      }
    }
    .width('100%')
    .height('100%')
    .padding(30)
    .justifyContent(FlexAlign.Center)
  }

  @Builder
  buildNewsContentPage(item: TabItemData, index: number) {
    Column({ space: 20 }) {
      Row({ space: 10 }) {
        Text(item.icon)
          .fontSize(24)
        Text(`${item.title}频道`)
          .fontSize(20)
          .fontWeight(FontWeight.Bold)
          .fontColor('#333333')
      }
      .width('100%')
      .padding({ left: 20, right: 20, top: 20 })
      List({ space: 15 }) {
        ForEach(this.newsData.filter(news =>
        item.title === '推荐' || news.category === item.title
        ), (news: NewsItemData) => {
          ListItem() {
            this.buildNewsItem(news)
          }
        })
      }
      .width('100%')
      .layoutWeight(1)
      .padding({ left: 20, right: 20 })
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F8F9FA')
  }

  @Builder
  buildSettingsPage(title: string, description: string) {
    Column({ space: 30 }) {
      Column({ space: 15 }) {
        Text('⚙️')
          .fontSize(48)
        Text(title)
          .fontSize(24)
          .fontWeight(FontWeight.Bold)
          .fontColor('#333333')
        Text(description)
          .fontSize(16)
          .fontColor('#666666')
          .textAlign(TextAlign.Center)
          .lineHeight(24)
      }
      Column({ space: 10 }) {
        this.buildSettingItem('🔧', '基础设置', '配置基本功能选项')
        this.buildSettingItem('🎨', '界面设置', '自定义界面外观')
        this.buildSettingItem('🔔', '通知设置', '管理通知提醒')
        this.buildSettingItem('🔒', '安全设置', '保护账户安全')
      }
    }
    .width('100%')
    .height('100%')
    .padding(30)
    .justifyContent(FlexAlign.Center)
  }

  @Builder
  buildCardContent(title: string, icon: string, color: string) {
    Column({ space: 20 }) {
      Text(icon)
        .fontSize(48)
        .fontColor(color)
      Text(title)
        .fontSize(24)
        .fontWeight(FontWeight.Bold)
        .fontColor('#333333')
      Text('这里是' + title + '的详细内容展示区域')
        .fontSize(16)
        .fontColor('#666666')
        .textAlign(TextAlign.Center)
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
    .backgroundColor('#FAFAFA')
  }

  @Builder
  buildDynamicTabContent(item: TabItemData, index: number) {
    Column({ space: 20 }) {
      Text(item.icon)
        .fontSize(40)
      Text(item.title)
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .fontColor('#333333')
      Text(`这是第${index + 1}个动态页签的内容`)
        .fontSize(16)
        .fontColor('#666666')
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }

  @Builder
  buildFeatureCard(icon: string, title: string, subtitle: string) {
    Column({ space: 10 }) {
      Text(icon)
        .fontSize(32)
      Text(title)
        .fontSize(14)
        .fontWeight(FontWeight.Medium)
        .fontColor('#333333')
      Text(subtitle)
        .fontSize(12)
        .fontColor('#999999')
        .textAlign(TextAlign.Center)
    }
    .width('100%')
    .height('100%')
    .padding(15)
    .backgroundColor(Color.White)
    .borderRadius(12)
    .justifyContent(FlexAlign.Center)
    .shadow({
      radius: 5,
      color: '#20000000',
      offsetX: 0,
      offsetY: 2
    })
  }

  @Builder
  buildNewsItem(news: NewsItemData) {
    Row({ space: 15 }) {
      Text('📰')
        .fontSize(24)
        .width(40)
        .textAlign(TextAlign.Center)
      Column({ space: 8 }) {
        Text(news.title)
          .fontSize(16)
          .fontWeight(FontWeight.Medium)
          .fontColor('#333333')
          .maxLines(2)
          .textOverflow({ overflow: TextOverflow.Ellipsis })
        Text(news.summary)
          .fontSize(14)
          .fontColor('#666666')
          .maxLines(2)
          .textOverflow({ overflow: TextOverflow.Ellipsis })
        Row({ space: 10 }) {
          Text(news.category)
            .fontSize(12)
            .fontColor('#3498DB')
            .backgroundColor('#E3F2FD')
            .padding({ left: 8, right: 8, top: 2, bottom: 2 })
            .borderRadius(10)
          Text(news.time)
            .fontSize(12)
            .fontColor('#999999')
        }
      }
      .alignItems(HorizontalAlign.Start)
      .layoutWeight(1)
    }
    .width('100%')
    .padding(15)
    .backgroundColor(Color.White)
    .borderRadius(12)
    .shadow({
      radius: 5,
      color: '#20000000',
      offsetX: 0,
      offsetY: 2
    })
  }

  @Builder
  buildSettingItem(icon: string, title: string, subtitle: string) {
    Row({ space: 15 }) {
      Text(icon)
        .fontSize(24)
        .width(40)
        .textAlign(TextAlign.Center)
      Column({ space: 5 }) {
        Text(title)
          .fontSize(16)
          .fontWeight(FontWeight.Medium)
          .fontColor('#333333')
        Text(subtitle)
          .fontSize(14)
          .fontColor('#666666')
      }
      .alignItems(HorizontalAlign.Start)
      .layoutWeight(1)
      Text('>')
        .fontSize(16)
        .fontColor('#C0C0C0')
    }
    .width('100%')
    .height(60)
    .padding({ left: 15, right: 15 })
    .backgroundColor(Color.White)
    .borderRadius(12)
    .shadow({
      radius: 5,
      color: '#20000000',
      offsetX: 0,
      offsetY: 2
    })
  }

  addTab() {
    const newTab: TabItemData = {
      id: this.tabItems.length + 1,
      title: `页签${this.tabItems.length + 1}`,
      icon: ['🎯', '⭐', '🔥', '💎', '🚀'][Math.floor(Math.random() * 5)],
      content: `这是新添加的页签内容`
    }
    this.tabItems.push(newTab)
  }

  removeTab(index: number) {
    if (this.tabItems.length > 1) {
      this.tabItems.splice(index, 1)
      if (this.currentIndex >= this.tabItems.length) {
        this.currentIndex = this.tabItems.length - 1
      }
    }
  }
}
⚙️ 配置文件
代码语言:javascript
复制
// module.json5 配置

{

  "module": {

    "name": "entry",

    "type": "entry",

    "description": "$string:module_desc",

    "mainElement": "EntryAbility",

    "deviceTypes": [

      "phone",

      "tablet"

    ],

    "deliveryWithInstall": true,

    "installationFree": false,

    "pages": "$profile:main_pages",

    "abilities": [

      {

        "name": "EntryAbility",

        "srcEntry": "./ets/entryability/EntryAbility.ts",

        "description": "$string:EntryAbility_desc",

        "icon": "$media:icon",

        "label": "$string:EntryAbility_label",

        "startWindowIcon": "$media:icon",

        "startWindowBackground": "$color:start_window_background"

      }

    ]

  }

}

🚀 运行效果

在这里插入图片描述
在这里插入图片描述
📱 界面展示

运行后的界面将展示:

  • 🎠 渐变色标题,展示Tabs组件主题
  • 🏷️ 四个Demo选择器:底部页签、顶部页签、垂直页签、自定义
  • 📑 底部页签:类似微信的底部导航栏,带徽章显示
  • 📰 顶部页签:新闻应用风格的可滚动页签
  • 📋 垂直页签:设置页面风格的侧边栏页签
  • 🎨 自定义页签:卡片式和动态页签展示
✅ 功能验证
  1. 页签切换:点击不同页签,观察切换动画效果
  2. 徽章显示:底部页签的消息徽章数字显示
  3. 滚动页签:顶部页签支持左右滚动查看更多
  4. 垂直布局:侧边栏样式的垂直页签布局
  5. 动态操作:自定义页签的添加和删除功能
  6. 样式变化:不同页签的激活状态样式变化

💡 开发小贴士

🎯 最佳实践
  • 💫 页签数量:底部页签建议3-5个,顶部页签可以更多
  • 🎨 视觉设计:保持页签样式一致性,突出当前激活状态
  • 性能优化:使用LazyForEach处理大量页签内容
  • 🔧 响应式设计:根据屏幕尺寸调整页签布局和字体大小
🚨 常见问题
  1. 页签切换卡顿:检查TabContent内容复杂度,考虑懒加载
  2. 徽章显示异常:确保徽章数字的数据类型和显示逻辑正确
  3. 自定义样式不生效:检查@Builder装饰器的使用和样式优先级
  4. 垂直页签布局问题:注意vertical属性和barWidth的设置
📚 扩展学习
  • 手势操作:添加左右滑动切换页签的手势支持
  • 页签预加载:实现相邻页签内容的预加载机制
  • 动画效果:自定义页签切换的过渡动画

🎉 总结与展望

通过这个Demo,我们学习了:

  • ✨ Tabs组件的基础使用和高级特性
  • 🎯 不同类型页签的设计和实现方法
  • 💡 自定义页签样式和交互的开发技巧
  • 🎨 创建美观页签界面的设计原则

Tabs组件作为现代移动应用中最重要的导航组件之一,掌握其各种用法对于创建优秀的用户体验至关重要。从简单的底部导航到复杂的多级页签,每一个细节都体现着应用的专业性和用户友好性。

希望这个示例能够帮助到正在学习HarmonyOS开发的你!下一期我们将探索更多有趣的UI组件,敬请期待!如果你有任何问题或建议,欢迎在评论区留言交流。


🔗 相关资源


🌟 如果这篇文章对你有帮助,请点赞支持!🌟

让我们一起在HarmonyOS的世界里创造更多可能!


© 2025 坚果派·红目香薰 | 用心分享,用技术创造价值

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-12-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ✨ 写在前面的话
  • 📋 Demo功能说明
    • 🎯 核心功能
    • ✨ 特色亮点
    • 🎨 界面展示
    • 📱 适用场景
  • 🔧 核心代码说明
    • 📁 项目结构
    • 🎯 关键技术点
      • 1. Tabs组件基础结构
      • 2. 自定义页签样式
      • 3. 页签控制属性
      • 4. 页签事件处理
    • 💡 技术要点解析
  • 📝 完整Demo代码
    • 🏠 主页面代码
    • ⚙️ 配置文件
  • 🚀 运行效果
    • 📱 界面展示
    • ✅ 功能验证
  • 💡 开发小贴士
    • 🎯 最佳实践
    • 🚨 常见问题
    • 📚 扩展学习
  • 🎉 总结与展望
  • 🔗 相关资源
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档