16 — Tabs 组件与 MSVTabs 封装

一、引言

breakpoint-system

短视频应用的核心交互是"多页签切换":首页、朋友、发布、消息、我的。HarmonyOS 提供 Tabs/TabContent 组件承载这一能力,但若每个页面各自维护一套 TabBar 样式,必然导致视觉漂移与维护成本上升。本项目在 common 层封装了 MSVTabs 公共组件,统一手机端底部页签与首页次级页签的样式交互,同时为 TV 智慧屏单独实现 TvTabs。本文结合 common/multishortvideobase/src/main/ets/components/MSVTabs.etsproducts/tv/src/main/ets/components/TvTabs.ets 讲解封装思路与多设备差异化。

二、Tabs/TabContent 基础用法

Tabs 由"页签栏 + 内容区"组成,TabContent 承载页面内容,通过 tabBar 属性自定义页签 UI:

Tabs({ index: this.activeIndex }) {
  TabContent() { HomePage() }.tabBar(this.MyTabBar(0))
  TabContent() { MinePage() }.tabBar(this.MyTabBar(1))
}
.barPosition(BarPosition.End)   // 页签位于底部
.barOverlap(true)               // 页签悬浮于内容之上
.onChange((index: number) => { this.activeIndex = index; })

常用属性:barPosition 控制页签栏位置(本项目底部 End / 顶部 Start)、barOverlap 控制页签是否悬浮(true)、barMode 控制 Fixed/Scrollable(BarMode.Scrollable)、barHeight 控制高度(56vp)。

三、MSVTabs 公共组件封装

MSVTabs 以数据驱动页签,配置收敛在 MSVDataModel(内容 Builder、文本、图标、是否仅图标):

export class MSVDataModel {
  public content?: BuilderCallback | null;   // 页签内容
  public text?: ResourceStr;                 // 页签文字
  public iconOnly?: boolean;                 // 是否纯图标
  public icon?: Resource;
  public iconDark?: Resource;                // 深色图标
  public iconSize?: Length;
}

组件对外参数(MSVTabs.ets):

@ComponentV2
export struct MSVTabs {
  @Require @Param data: MSVDataModel[];       // 必传
  @Local activeIndex: number = 0;             // 内部选中态
  @Param useFloating: boolean = true;         // 悬浮 TabBar
  @Param index: number = 0;                   // 初始索引
  @Param showBarUnderline: boolean = false;   // 选中下划线
  @Param barPosition: BarPosition = BarPosition.Start;
  @Param onIndexChange: (index: number) => void = () => {};

  aboutToAppear(): void { this.activeIndex = this.index; }
}

@Require @Param 强制调用方传 data;@Local activeIndex 内部维护选中态;onIndexChange 把切换事件抛给外部(如切到"我的"时切换深浅色)。

四、自定义 TabBar 构建

MSVTabs 用 @Builder 定义页签样式,区分"纯图标"与"图标+文字",支持选中下划线:

@Builder
MSVTabBar(params: MSVDataModel, currentIndex: number) {
  if (params.iconOnly) {
    Image(this.isDark ? params.iconDark : params.icon)
      .width(params.iconSize).aspectRatio(1)
  } else {
    Column() {
      Text(params.text)
        .fontColor(this.activeIndex === currentIndex ? this.selectedLightColor : this.lightColor)
    }
    .border({ width: { bottom: this.showBarUnderline && (this.activeIndex === currentIndex) ? 1 : 0 } })
  }
}

MainTabsViewModel 中"发布"页签即纯图标形态(加号):

this.mainTabsData.push(new MSVDataModel(home, $r('app.string.home_title')));
this.mainTabsData.push(new MSVDataModel(add, '', true, $r('app.media.ic_plus'), $r('app.media.ic_plus_dark')));

其余"朋友、消息、我的"为图文形态,仅传文本与内容 Builder。

五、HdsTabs 悬浮页签与降级策略

大屏启用系统 HDS 悬浮页签,小屏或不支持时降级为原生 Tabs,用 canIUse 能力探测 + useFloating 开关双轨控制:

if (canIUse('SystemCapability.UIDesign.HDSComponent.Core') && this.useFloating) {
  HdsTabs({ index: this.activeIndex }) { this.MSVTabContent(this.data) }
    .barPosition(BarPosition.End)
    .barFloatingStyle({ barSideMargin: 16, barBottomMargin: this.barBottomMargin, ... })
    .barHeight(44)
} else {
  Tabs({ index: this.activeIndex }) { this.MSVTabContent(this.data) }
    .barPosition(this.barPosition)
    .barBackgroundBlurStyle(BlurStyle.NONE)
    .barHeight(56).barMode(BarMode.Scrollable, { margin: 8 })
}

首页次级页签 SubTabs(SubTabsComponent.ets)关闭悬浮并开启下划线:useFloating: false, index: 4, showBarUnderline: true,数据来自 SubTabsViewModel(商城、直播、关注、推荐等)。

六、TV 端 TvTabs 差异化

TV 端无触摸,TvTabs 用横向 List 构建页签,选中态由全局 currentBottomIndex 驱动,天然支持遥控器聚焦:

@ComponentV2
export struct TVTabs {
  @Consumer('currentBottomIndex') currentBottomIndex: number = 2;
  @Local btnList: Array<Resource> = [推荐, 关注, 朋友, 加号, 消息, 我的];
  // 横向 List 渲染,当前项高亮背景与文字色
}

与 MSVTabs 的差异对比如下:

维度MSVTabs(手机/平板)TvTabs(智慧屏)

容器Tabs / HdsTabs横向 List
位置底部悬浮或顶部顶部居中胶囊
交互点击、滑动遥控器方向键 + 点击
状态@Param + @Local@Consumer 全局索引

七、总结与最佳实践

  • 用数据模型驱动页签,新增页签只加一条数据,内容与图标统一收敛。
  • 参数化 + @Builder 自定义 TabBar,一套组件覆盖底部、顶部、纯图标、下划线多种形态。
  • canIUse 探测 + useFloating 开关实现 HDS 悬浮与原生 Tabs 双轨降级。
  • 设备差异收敛在产品层:手机/平板复用 MSVTabs,TV 独立实现 TvTabs。
  • onIndexChange 只抛事件不写业务,保证公共组件与业务解耦。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐