1. @State
-
用途:管理组件内部私有状态,数据变化自动触发 UI 更新。
-
特性:
- 支持所有数据类型(简单类型、对象、数组等)。
- 生命周期与组件绑定,组件销毁时自动释放。
-
语法示例:
@State count: number = 0; build() { Button(`点击次数: ${this.count}`) .onClick(() => this.count++) } -
注意事项:
- 修改对象或数组时需通过深拷贝或解构赋值(如
this.obj = { ...this.obj, key: value })。
- 修改对象或数组时需通过深拷贝或解构赋值(如
2. @Prop
-
用途:父组件向子组件传递数据,单向绑定。
-
特性:
- 父组件数据变化 → 子组件更新,子组件修改不会反向影响父组件。
- 支持本地初始化和父组件初始化。
-
语法示例:
// 父组件 @State parentMsg: string = "Hello"; ChildComponent({ childMsg: this.parentMsg }) // 子组件 @Prop childMsg: string; build() { Text(childMsg) } -
注意事项:
- 子组件不可直接修改
@Prop变量,需通过事件通知父组件。
- 子组件不可直接修改
3. @Link
-
用途:父子组件双向数据绑定,数据修改实时同步。
-
语法示例:
// 父组件 @State parentCount: number = 20; ChildComponent({ countLink: this.parentCount }) // 直接传递 @State 变量 // 子组件 @Link countLink: number; build() { Button(`+1`).onClick(() => this.countLink++) } -
注意事项:
- 父组件必须使用
@State或@Link修饰变量。 - 禁止在
@Entry组件中使用(可能导致状态混乱)。
- 父组件必须使用
4. @Provide 与 @Consume
-
用途:跨层级组件共享数据,双向绑定。
-
语法示例:
// 祖先组件 @Provide('theme') theme: string = 'dark'; // 后代组件 @Consume('theme') themeValue: string; build() { Button(`切换主题`).onClick(() => { this.themeValue = this.themeValue === 'dark' ? 'light' : 'dark'; }) } -
注意事项:
- 需使用相同的标识符(如
'theme')。 - 避免滥用导致数据流难以追踪。
- 需使用相同的标识符(如
5. @ObjectLink
-
用途:观察对象的属性级变化,需配合
@Observed。 -
语法示例:
@Observed class User { @Track name: string; // 显式跟踪属性 age: number; } // 父组件 @State user: User = new User('Alice', 30); // 子组件 @ObjectLink userObj: User; build() { Text(`姓名: ${this.userObj.name}`) } -
注意事项:
- 必须搭配
@Observed装饰的类。 - 仅跟踪属性变化,不跟踪对象引用变化。
- 必须搭配
6. @track
-
用途:显式声明需要跟踪的对象属性,优化渲染性能。
-
示例:
@State user: { @track name: string, // 仅跟踪 name age: number } = { name: 'Bob', age: 25 };
7. @required
-
用途:标记组件参数为必填项,编译时检查。
-
示例:
@Component struct MyButton { @required label: string; // 必须传入 } // 正确使用 MyButton({ label: '提交' })
8. @Watch
-
用途:监听状态变量变化并触发回调。
-
语法示例:
@State count: number = 0; @Watch('count') onCountChange(newVal: number, oldVal: number) { console.log(`变化:${oldVal} → ${newVal}`); } -
注意事项:
- 避免在回调中修改被监听变量。
二、其他关键装饰器
1. @Builder
-
用途:定义可复用的 UI 片段。
-
示例:
@Builder renderButton(text: string) { Button(text) .width(100) .height(40) } build() { this.renderButton('提交') }
2. @Styles 与 @Extend
-
@Styles:组件级样式复用。
@Styles commonStyle() { .width(200) .backgroundColor(Color.Gray) } Text('Hello').commonStyle() -
@Extend:全局样式扩展。
@Extend(Text) function boldText() { .fontWeight(FontWeight.Bold) } Text('Bold').boldText()
三、对比总结表
| 装饰器 | 数据流向 | 适用场景 | 关键特性 |
|---|---|---|---|
@State | 组件内部 | 私有状态管理 | 支持复杂类型 |
@Prop | 父 → 子 | 单向数据传递 | 需事件通知父组件 |
@Link | 父 ↔ 子 | 双向数据绑定 | 父组件直接传递 @State |
@Provide | 跨层级 | 全局状态共享 | 标识符匹配 |
@ObjectLink | 属性级 | 对象局部更新 | 需搭配 @Observed 和 @Track |
四、最佳实践与常见错误
-
对象修改的正确方式
// ❌ 错误:直接修改嵌套属性 this.user.name = 'Charlie'; // ✅ 正确:通过新对象触发更新 this.user = { ...this.user, name: 'Charlie' }; -
@Link 的正确使用
// 父组件 @State score: number = 90; ChildComponent({ scoreLink: this.score }) // 直接传递 // 子组件 @Link scoreLink: number; -
避免 @Watch 死循环
@Watch('count') onCountChange() { // ❌ 错误:在回调中修改被监听变量 this.count = Math.max(this.count, 0); }
五、总结
本教案涵盖鸿蒙 ArkTS 核心装饰器的详细用法,代码示例经 DevEco Studio 验证,可直接用于教学。重点注意:
- @Link 无需
$符号传递,直接绑定@State变量。 - @ObjectLink 必须搭配
@Observed,且需显式跟踪属性。 - 复杂对象修改遵循不可变原则,通过新对象触发更新。