鸿蒙 ArkTS 装饰器看我就够了

360 阅读2分钟

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

四、最佳实践与常见错误

  1. 对象修改的正确方式

    // ❌ 错误:直接修改嵌套属性  
    this.user.name = 'Charlie';  
     
    // ✅ 正确:通过新对象触发更新  
    this.user = { ...this.user, name: 'Charlie' };  
    
  2. @Link 的正确使用

    // 父组件  
    @State score: number = 90;  
    ChildComponent({ scoreLink: this.score }) // 直接传递  
     
    // 子组件  
    @Link scoreLink: number;  
    
  3. 避免 @Watch 死循环

    @Watch('count')  
    onCountChange() {  
      // ❌ 错误:在回调中修改被监听变量  
      this.count = Math.max(this.count, 0);  
    }  
    

五、总结

本教案涵盖鸿蒙 ArkTS 核心装饰器的详细用法,代码示例经 DevEco Studio 验证,可直接用于教学。重点注意:

  • @Link 无需 $ 符号传递,直接绑定 @State 变量。
  • @ObjectLink 必须搭配 @Observed,且需显式跟踪属性。
  • 复杂对象修改遵循不可变原则,通过新对象触发更新。