HarmonyOS 多设备短视频开发 : 20 — 自定义组件与 @Builder/@BuilderParam
20 — 自定义组件与 @Builder/@BuilderParam
一、引言

当同一 UI 片段在多个页面反复出现(图标、头像、页签),将其封装为自定义组件是 ArkUI 声明式开发的基本功;而"占位 + 插槽"则让公共壳子具备无限扩展性。本项目通过自定义组件 MSVTextIcon、@Builder 构建函数与 @BuilderParam 插槽,实现了公共 Builder 复用与插槽化设计,支撑"同一页面多种外壳"的多设备策略。本文以 common/multishortvideobase/src/main/ets/components/MSVTextIcon.ets、products/default/src/main/ets/components/Builders.ets、features/multishortvideoindividual/src/main/ets/components/Builders.ets 为主线。
二、自定义组件结构与生命周期
MSVTextIcon 将"图标 + 可选文字"组合为可配置组件,头像、点赞、搜索、分享等场景复用:
@ComponentV2
export struct MSVTextIcon {
@Require @Param src: PixelMap | ResourceStr | DrawableDescriptor;
@Param iconSize: Length = 32;
@Param iconOnly: boolean = true;
@Param content: string | Resource = '';
@Param fontSize: ... = $r('sys.float.Body_M');
@Param gap: Length = 2;
build() {
Column({ space: this.gap }) {
Image(this.src).width(this.iconSize).aspectRatio(1).objectFit(ImageFit.Contain)
if (!this.iconOnly) {
Text(this.content).fontSize(this.fontSize).fontColor(this.fontColor)
}
}
}
}设计要点:@Require @Param 标记必传参数 src,编译期约束调用方;其余 @Param 提供默认值,调用方按需覆盖(如评论头像 iconSize: deviceInfo.deviceType === 'tv' ? 44 : 32);组件自带 aboutToAppear/aboutToDisappear 生命周期,可做数据加载与资源释放。
三、@Builder 局部构建函数
@Builder 将一段 UI 封装为可复用构建函数,支持参数传递。MSVTabs 用它定义页签样式:
@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 } })
}
}SplitComment 用 @Builder 定义自定义标题栏(渐变遮罩 + 标题 + 关闭按钮):
@Builder
CustomTitleBuilder() {
Column() {
Column().width(CommonConstants.FULL_PERCENT).height(36)
.linearGradient({ direction: GradientDirection.Bottom, colors: [['#4D000000', 0.0], ['#00000000', 1.0]] })
Row() {
Text($r('app.string.comment_title', this.commentCount))
Row() { SymbolGlyph($r('sys.symbol.xmark')).fontSize(18) }
.onClick(() => { this.pathStack.pop(); this.showSideComment = false; })
}
}
}四、@BuilderParam 内容插槽
@BuilderParam 接收外部传入的 Builder,形成"占位-填充"插槽。MSVTabs 内部封装 MSVTabContent,让每个 TabContent 的内容由调用方决定:
@ComponentV2
struct MSVTabContent {
@Local stackId: string = 'MSVTabContent';
@BuilderParam content: BuilderCallback; // 外部注入的页签内容
build() {
Stack() {
this.content()
}
.id(this.stackId)
}
}使用侧把页签内容 Builder 传入:
@Builder
MSVTabContent(data: MSVDataModel[]) {
ForEach(data, (tabItem: MSVDataModel, index: number) => {
TabContent() {
if (tabItem.content) {
MSVTabContent({ content: tabItem.content })
}
}
.tabBar(this.MSVTabBar(tabItem, index))
}, (tabItem: MSVDataModel) => JSON.stringify(tabItem.content))
}BuilderCallback 是 ArkUI 通用构建函数类型,@BuilderParam 与导出 @Builder 天然兼容。
五、Builders.ets 公共 Builder 复用
产品层将页面级 Builder 统一收敛在 Builders.ets,作为 MSVDataModel.content 注入页签,实现"数据驱动 + 内容可换":
// products/default/.../components/Builders.ets
@Builder export function home() {
SubTabs().width(CommonConstants.FULL_PERCENT).height(CommonConstants.FULL_PERCENT)
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
}
@Builder export function recommend() {
Column() { AdaptiveVideoForDefault() }
.width(CommonConstants.FULL_PERCENT).height(CommonConstants.FULL_PERCENT)
.backgroundColor(Color.Black)
}individual 模块的 Builders.ets 同样导出作品页等:@Builder export function works() { Column() { Works() } ... }。数据层直接引用 Builder 完成页签组装(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')));六、插槽化设计在个人作品页与评论区头部的应用
个人作品页 Individual.ets 的头部信息区与 MSVTabs 内容区解耦;评论区头部(CustomTitleBuilder)与评论列表(Comment)解耦。二者共享同一模式:外壳组件只负责布局与关闭逻辑,业务内容通过 @Builder/插槽注入,实现"同一评论页面,手机半模态、大屏分栏、TV 全屏三种外壳"下内容零重复。
| 应用场景 | 壳组件 | 插槽/组合内容 | 多形态 |
| 评论区 | SplitComment / bindSheet | Comment | 半模态、分栏、全屏 |
| 个人主页 | IndividualByRouter | Individual | 全屏、侧面板 |
| 底部页签 | MSVTabs + MSVTabContent | Builders.ets 各页面 | 手机/TV/PC |
七、总结与最佳实践
- 高频 UI 片段封装为自定义组件(MSVTextIcon),必传参数用 @Require @Param,可选参数给默认值。
- 组件内复用用 @Builder,跨模块复用用导出 @Builder(Builders.ets)。
- @BuilderParam 提供插槽能力,壳组件与业务内容彻底解耦,支撑"一内容多外壳"。
- 页面内容以 Builder 注入 MSVDataModel,实现页签数据驱动、内容可热替换。
- 生命周期方法保持轻量,aboutToAppear 只做数据加载,避免卡顿。
更多推荐




所有评论(0)