✨ 第7章 装饰器与组件基础
装饰器是 ArkTS / ArkUI 的核心魔法 —— @Component、@State、@Prop 等将普通类变为可响应的 UI 组件。理解装饰器,就掌握了 ArkUI 的灵魂。
8.1 7.1 什么是装饰器
定义
装饰器(Decorator)是以 @ 开头的特殊标注,用于修饰类、属性或方法,附加额外的行为或元数据,而无需修改原始代码。
💡 类比理解
装饰器就像给礼物贴标签 🎁:@Component → 贴上"这是UI组件"@State → 贴上"这个变量变化时刷新界面"@Entry → 贴上"这是页面入口"
装饰器的分类概览:
| 装饰器 | 作用范围 | 功能描述 |
|---|---|---|
@Component |
结构体 struct | 声明一个自定义 UI 组件 |
@Entry |
@Component 组件 | 声明页面入口组件 |
@State |
成员变量 | 组件内部状态,变化触发 UI 刷新 |
@Prop |
成员变量 | 父组件传入的属性(单向绑定) |
@Link |
成员变量 | 父子组件双向数据绑定 |
@Observed |
类 | 监听嵌套对象属性变化 |
@Provide/@Consume |
成员变量 | 跨层级组件数据共享 |
@Builder |
方法 | 自定义构建函数(UI 片段) |
@Styles |
方法 | 封装复用样式 |
@Watch |
成员变量 | 监听状态变量变化,触发回调 |
8.2 7.2 @Component 与 @Entry
这是 ArkUI 最基础的两个装饰器:
// @Entry 标记页面入口,每个页面只有一个
@Entry
@Component
struct IndexPage {
// 页面内容
build() {
Column() {
Text("欢迎使用 ArkTS!")
.fontSize(24)
.fontColor('#C02020')
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
}💡 struct vs class
ArkUI 组件使用 struct(结构体)而非 class,这是 ArkTS 的特殊设计。struct 不支持继承,但可组合,这使得 UI 组件树更简洁可预测。
8.3 7.3 @State —— 状态驱动 UI
@State 是 ArkUI 响应式的核心:状态变了,UI 自动刷新。
@Entry
@Component
struct CounterPage {
@State count: number = 0; // 状态变量
build() {
Column({ space: 20 }) {
Text(`计数:${this.count}`)
.fontSize(32)
.fontWeight(FontWeight.Bold)
Row({ space: 12 }) {
Button("-1")
.onClick(() => { this.count--; }) // 修改 State → 自动刷新
Button("+1")
.onClick(() => { this.count++; })
Button("重置")
.onClick(() => { this.count = 0; })
}
}
.width('100%').height('100%').justifyContent(FlexAlign.Center)
}
}📱 @State 计数器模拟
HarmonyOS 模拟器
@State count: number
0
UI 状态日志
8.4 7.4 @Prop 与 @Link —— 父子通信
// 子组件:接收父组件传入的值(单向)
@Component
struct ChildCard {
@Prop title: string; // 父→子,单向
@Link sharedCount: number; // 父↔子,双向
build() {
Column() {
Text(this.title).fontSize(16)
Button(`点击(${this.sharedCount})`)
.onClick(() => { this.sharedCount++; }) // 会影响父组件
}
}
}
// 父组件
@Entry
@Component
struct ParentPage {
@State myCount: number = 0;
build() {
Column() {
Text(`父组件 count: ${this.myCount}`)
// @Link 需要用 $变量名 传递引用
ChildCard({ title: "子卡片A", sharedCount: $myCount })
ChildCard({ title: "子卡片B", sharedCount: $myCount })
}
}
}🔗 @Prop / @Link 父子通信演示
📦 父组件
@State myCount0
共享状态
🃏 子组件A
@Link sharedCount🃏 子组件B
@Prop title(只读)子卡片B
@Prop 单向展示
点击子组件A查看双向绑定效果...
8.5 7.5 @Builder —— UI 片段复用
@Entry
@Component
struct BuilderDemo {
@State likes: number = 0;
// @Builder 装饰器:定义可复用的 UI 片段
@Builder
LikeButton(label: string) {
Button(`❤️ ${label} (${this.likes})`)
.backgroundColor('#C02020')
.onClick(() => { this.likes++; })
}
build() {
Column({ space: 12 }) {
Text("@Builder 复用示例").fontSize(20)
this.LikeButton("点赞文章") // 复用
this.LikeButton("点赞评论") // 复用
}
.width('100%').padding(20)
}
}8.6 7.6 @Watch —— 监听状态变化
@Entry
@Component
struct WatchDemo {
@State @Watch('onCountChange') count: number = 0;
@State history: string[] = [];
// 当 count 变化时自动触发
onCountChange() {
this.history.push(`count 变为 ${this.count}`);
if (this.count > 10) {
console.log("警告:count 超过 10!");
}
}
build() {
Column() {
Button(`+1 (${this.count})`).onClick(() => { this.count++; })
ForEach(this.history, (h: string) => {
Text(h).fontSize(12).fontColor('#666')
})
}
}
}8.7 7.7 章末总结
📌 核心记忆
- @Component:每个 ArkUI 自定义组件必须
- @Entry:页面唯一入口,和 @Component 搭配
- @State:组件私有状态,变化自动刷新 UI
- @Prop:父→子单向传值(子不能改)
- @Link:父↔子双向绑定(用
$变量名传递) - @Builder:封装可复用的 UI 片段
- @Watch:监听状态变化,执行副作用逻辑