🎯 什么是 @Builder
?
在 ArkTS 中,@Builder
是一个装饰器(Decorator) ,用于修饰一个函数,使其成为可以在 UI 构建中直接调用的结构函数(UI Builder Function)。
它的设计目标是:
将一段可复用、无状态的 UI 结构以函数形式封装起来,以便灵活复用和组合。
🧠 本质理解:@Builder
≠ @Component
特性 | @Builder |
@Component |
---|---|---|
本质 | UI 结构的函数封装(无状态) | 状态驱动的 UI 单元(组件) |
生命周期支持 | ❌ 不支持 | ✅ 支持 aboutToAppear 等生命周期 |
响应式变量 | ❌ 不支持定义状态,只能通过参数传入 | ✅ 内部可使用 @State , @Prop 等 |
渲染方式 | 函数调用:this.myBuilder() |
组件标签:<MyComponent /> |
渲染目标 | 插入父组件的 UI 树 | 独立的虚拟 DOM 节点 |
📦 为什么需要 @Builder
?
想象你要创建多个样式一样的按钮、卡片、列表项:
ts
Button('提交').width(100).backgroundColor(Color.Blue)
Button('取消').width(100).backgroundColor(Color.Blue)
Button('重置').width(100).backgroundColor(Color.Blue)
有没有重复?有。
有没有状态?没有。
这时你可以这样做:
ts
@Builder
function StyledButton(label: string) {
Button(label).width(100).backgroundColor(Color.Blue)
}
这样做有 4 个好处:
- ✅ 避免重复代码
- ✅ 提高可维护性
- ✅ 提高可读性
- ✅ 支持参数自定义(可动态渲染)
🔧 @Builder
的工作机制
当你使用:
ts
@Builder
function myBuilder(...) {
// UI结构
}
ArkTS 会将该函数编译为 UI Fragment 构造函数,这个函数在调用时:
- 被插入到调用处的 UI 构建树中
- 会按传入参数,构建对应的视图结构
- 不会绑定状态或响应式机制,因此无任何状态监听器或更新订阅器。
即:纯粹的 UI 构造器 + 参数驱动的"组件函数"
🧪 参数传递机制详解
✅ 按值传递(默认)
ts
@Builder
function StaticText(text: string) {
Text(text) // 传的是固定值
}
text
是只读值 ,即使父组件变量变了,StaticText
中不会更新 UI。- 适合不变化的数据。
✅ 按引用传递($$
)
ts
@Builder
function ReactiveText(text: $$string) {
Text(text) // 响应父组件的状态变化
}
- 传入的是响应式引用(state 或 prop)
- 当
text
的值改变,UI 会自动刷新 - 实现方式是通过内部的状态绑定机制,监听数据变化触发 UI 更新
🧩 @BuilderParam
:构建函数作为参数传入
ts
@Component
struct MyContainer {
@BuilderParam slot: () => void
build() {
Column() {
this.slot() // 插入外部传来的 UI 构建函数
}
}
}
用法场景类似于:
- React 中的
props.children
- Vue 中的
<slot>
- 插槽化 UI 设计,让 UI 可组合、可注入
🔁 动态布局组合:@Builder
的高级用法
你可以根据条件选择不同构建函数:
ts
@Builder
function RedBox() {
Text('Red').backgroundColor(Color.Red)
}
@Builder
function GreenBox() {
Text('Green').backgroundColor(Color.Green)
}
@Component
struct SwitchBox {
@State color: string = "red"
build() {
Column() {
(this.color === 'red' ? this.RedBox : this.GreenBox)()
}
}
}
@Builder
实际就是可变的 UI 结构"模板",可以灵活组合。
⚠️ 注意事项 & 限制
项目 | 说明 |
---|---|
❌ 不支持状态变量 | 无法定义 @State ,只能通过参数传入 |
❌ 没有生命周期 | 无法使用 aboutToAppear 等生命周期钩子 |
✅ 可嵌套 | @Builder 中可以调用其他 @Builder |
❌ 无法访问组件状态 | 全局 Builder 函数中无法访问当前组件内状态 |
✅ 支持列表渲染 | 可结合 LazyForEach 动态渲染大量结构 |
✅ 推荐实践指南
目的 | 推荐做法 |
---|---|
封装小段 UI(如按钮) | 使用 @Builder |
需要状态/生命周期/交互 | 使用 @Component |
重复 UI 样式统一管理 | 提取为 @Builder 函数 |
动态组合布局 | 将多个 Builder 按条件组合调用 |
插槽式 UI(传 UI 做参数) | 使用 @BuilderParam |
📌 示例:构建统一的卡片组件样式
ts
@Builder
function InfoCard(title: string, content: string) {
Column() {
Text(title).fontSize(20).fontWeight(FontWeight.Bold)
Text(content).margin({ top: 10 })
}
.padding(20)
.backgroundColor(Color.White)
.borderRadius(8)
}
在多个组件中:
ts
InfoCard("通知", "这是一条消息")
InfoCard("警告", "网络已断开")