把重复的UI代码提取成方法------@Builder是ArkUI的"组件函数"

什么是@Builder
@Builder是ArkTS的装饰器,用于定义可复用的UI构建方法。它类似于"轻量级组件"------不需要声明struct,但可以包含完整的UI代码。
本项目的@Builder使用
AIBattlePage使用了4个@Builder方法:
typescript
@Builder
levelSelectView() { /* 关卡选择视图 */ }
@Builder
levelCard(item: LevelConfig) { /* 关卡卡片 */ }
@Builder
gameView() { /* 游戏对战视图 */ }
@Builder
resultDialog() { /* 结果弹窗 */ }
@Builder的调用
typescript
build() {
Stack() {
Column() {
// 导航栏...
if (this.inGame) {
this.gameView() // 调用@Builder方法
} else {
this.levelSelectView() // 调用@Builder方法
}
}
if (this.inGame && this.showResultDialog) {
this.resultDialog() // 调用@Builder方法
}
}
}
@Builder方法可以用this.xxx()在build()中调用,就像普通方法一样。
@Builder vs 自定义组件
| 特性 | @Builder | @Component struct |
|---|---|---|
| 声明方式 | 方法 | struct |
| 参数传递 | 方法参数 | @Prop/@Link |
| 状态管理 | 共享宿主组件状态 | 独立状态 |
| 复用性 | 仅限当前组件 | 跨文件复用 |
| 适合场景 | 组件内UI拆分 | 独立可复用组件 |
为什么AIBattlePage用@Builder
AIBattlePage有两个主要视图(选关、游戏)和一个弹窗,如果全部写在build()中会非常冗长。用@Builder拆分后:
typescript
build() {
Stack() {
Column() {
// 导航栏(共用)
Row() { ... }
// 根据状态选择视图
if (this.inGame) {
this.gameView() // 100+行UI代码被封装
} else {
this.levelSelectView() // 50+行UI代码被封装
}
}
if (this.inGame && this.showResultDialog) {
this.resultDialog() // 80+行UI代码被封装
}
}
}
build()方法变得简洁清晰。
@Builder方法内部访问状态
typescript
@Builder
gameView() {
Column() {
// 直接访问宿主组件的@State
Text(this.getStatusText())
if (this.aiThinking) {
LoadingProgress()
}
ChessBoardView({
boardData: this.boardData,
onCellClick: (row: number, col: number) => {
this.onCellClick(row, col);
}
})
}
}
@Builder方法可以直接访问宿主组件的所有成员变量和方法------不需要参数传递。
@Builder带参数
typescript
@Builder
levelCard(item: LevelConfig) {
Button() {
Row({ space: 16 }) {
Text(item.icon)
.backgroundColor(item.color)
Column() {
Text(`第${item.level}关`)
Text(item.name)
Text(item.desc)
}
}
}
.enabled(item.level <= this.unlockedLevel) // 仍可访问宿主状态
}
参数item是LevelConfig类型,在ForEach中传入:
typescript
ForEach(this.levels, (item: LevelConfig) => {
this.levelCard(item) // 传参调用
}, (item: LevelConfig) => item.level.toString())
@Builder的嵌套调用
typescript
@Builder
levelSelectView() {
Column({ space: 16 }) {
Text('选择关卡')
ForEach(this.levels, (item: LevelConfig) => {
this.levelCard(item) // @Builder调用@Builder
}, (item: LevelConfig) => item.level.toString())
}
}
@Builder方法可以调用其他@Builder方法------形成UI的模块化组合。
ChessBoardView为什么不用@Builder
ChessBoardView是独立组件(@Component export struct),不是@Builder------因为它需要跨文件复用(被TwoPlayerPage和AIBattlePage共用)。
选择原则:
- 仅在当前组件内使用的UI片段 → @Builder
- 需要跨组件/跨文件复用 → @Component struct
总结
@Builder是ArkUI中组织UI代码的重要工具:
- 代码拆分:将冗长的build()方法分解为逻辑单元
- 状态共享:直接访问宿主组件的状态
- 参数传递:支持方法参数
- 嵌套调用:@Builder可以调用@Builder
- 适用场景:组件内的UI复用,不需要跨文件
合理使用@Builder可以让复杂的UI代码保持清晰和可维护。