🎯 组件相关的装饰器

这类装饰器是构建UI的基石,用于定义组件及其状态。

  • @Component与@Entry
    使用 @Component 装饰的struct结构体,就是一个可复用的自定义组件。每个组件都必须实现build方法,在其中描述UI。
    @Entry 则是一个特殊的装饰器,它用于标记该组件是页面的入口组件。一个页面有且仅有一个@Entry装饰的组件,它作为UI组件的根节点。

  • @State:组件的“私有状态”
    @State装饰的变量是组件内部的状态。当它的值发生变化时,会触发所在组件的UI重新渲染

    @Component
    struct MyComponent {
      @State count: number = 0; // 改变count,Text的内容会更新
    
      build() {
        Column() {
          Text(`Count: ${this.count}`)
          Button('Click me')
            .onClick(() => {
              this.count++; // 点击按钮,count变化,UI更新
            })
        }
      }
    }

  • @Prop与@Link:父子组件间的数据纽带
    这两个装饰器用于在父子组件之间传递数据。

    • @Prop 建立单向绑定。子组件接收父组件传递过来的值,但子组件内对@Prop变量的修改,不会同步回父组件

    • @Link 建立双向绑定。子组件不仅可以接收父组件的值,其自身的修改也能同步回父组件,双方的数据保持一致。

    // 子组件
    @Component
    struct ChildComponent {
      @Prop propValue: number; // 单向
      @Link @Watch('linkChange') linkValue: number; // 双向
    
      linkChange() {
        console.log('linkValue changed:', this.linkValue);
      }
    
      build() {
        Row() {
          Text(`Prop: ${this.propValue}, Link: ${this.linkValue}`)
          Button('Change in Child')
            .onClick(() => {
              this.propValue++; // 仅子组件内变化
              this.linkValue++; // 会同步回父组件
            })
        }
      }
    }
    
    // 父组件
    @Entry
    @Component
    struct ParentComponent {
      @State parentCount: number = 0;
    
      build() {
        Column() {
          ChildComponent({ propValue: this.parentCount, linkValue: $parentCount })
          Text(`Parent Count: ${this.parentCount}`) // 点击子组件按钮,这个值会因linkValue改变而更新
        }
      }
    }

    上面的例子还展示了@Watch装饰器的用法,它用于监听状态变量的变化,当变量改变时,会触发指定的回调函数。

  • @Provide与@Consume / @Provider与@Consumer:跨组件层级的“直达通道”
    当需要跨越多层组件传递数据时,使用@Provide@Consume(或状态管理V2中的@Provider@Consumer)可以避免逐层传递的麻烦。

    • 数据提供方使用@Provide(或V2的@Provider)装饰变量。

    • 数据消费方使用@Consume(或V2的@Consumer)装饰变量,它会自动查找并绑定到最近父组件的同名@Provide/@Provider变量上

    // 状态管理V1示例
    @Component
    struct GrandParent {
      @Provide money: number = 100; // 提供数据
    }
    
    @Component
    struct Parent {
      build() {
        Column() {
          Child()
        }
      }
    }
    
    @Component
    struct Child {
      @Consume money: number; // 消费数据,直接找到GrandParent的money
    
      build() {
        Text(`My allowance: ${this.money}`)
      }
    }

    状态管理V2中,@Provider@Consumer的功能类似,但它们是@ComponentV2的专属装饰器,且在细节上有所优化,例如@Consumer允许本地初始化,当找不到@Provider时使用本地默认值。

💅 样式与功能增强装饰器

这类装饰器不直接参与状态管理,但能极大提升开发效率与代码复用。

  • @Styles:提取公共样式
    当多个组件需要复用同一套样式时,@Styles可以帮你将样式属性提炼成一个方法,减少重复代码。

    @Entry
    @Component
    struct MyComponent {
      @Styles reuseStyle() {
        .backgroundColor(Color.Orange)
        .width(200)
        .margin(10)
      }
    
      build() {
        Column() {
          Text('1').reuseStyle() // 应用公共样式
          Text('2').reuseStyle()
          Text('3').reuseStyle()
        }
      }
    }

    需要注意的是,@Styles方法不支持参数,且仅支持通用属性和通用事件。

  • @Extend:扩展原生组件样式
    @Extend 装饰器能让你扩展原生组件的样式,并且支持参数,比@Styles更加灵活。它仅支持在全局定义

    @Extend(Text) // 扩展Text组件
    function textStyle(w: number) {
      .width(w)
      .backgroundColor(Color.Green)
      .margin(10)
    }
    
    @Entry
    @Component
    struct MyComponent {
      build() {
        Column() {
          Text('A').textStyle(100) // 传入参数
          Text('B').textStyle(150)
        }
      }
    }

  • @Builder:构建可复用的UI片段
    @Builder装饰的函数可以帮助你构建可复用的UI描述片段,类似于一个轻量级的、没有状态的组件。它可以在单个组件内使用(@Builder),也可以定义为全局的(@Builder function)。

    @Entry
    @Component
    struct MyComponent {
      @Builder myBuilderBuilder() {
        Column() {
          Text('From Builder')
            .fontSize(20)
            .backgroundColor(Color.Blue)
        }
      }
    
      build() {
        Column() {
          this.myBuilderBuilder() // 使用Builder
        }
      }
    }

🚀 状态管理V2装饰器简介

随着HarmonyOS的发展,状态管理V2装饰器(需与@ComponentV2配合使用)带来了更精细化的数据观察和组件设计。

  • @Local:可理解为V2版本的@State,用于组件内部状态管理。

  • @Param:可理解为V2版本的@Prop,用于接收父组件传入的数据。在V2中,如果希望子组件可以修改@Param变量且不同步回父组件,需要配合@Once装饰器。

  • @Event:用于规范子组件向父组件传递事件(数据双向绑定),是实现V2中子组件修改父组件数据的推荐方式。

  • @ObservedV2与@Trace:这对组合解决了V1中深层嵌套对象观察的痛点。@ObservedV2装饰类,@Trace装饰该类中需要被观察的特定属性,实现了属性级深度观察,无需再像V1那样层层使用@ObjectLink

💎 装饰器使用小结

为了方便你记忆和区分,下面用一个表格总结核心装饰器的用途:

装饰器 主要用途 数据流向
@State 组件内部状态管理 组件内部
@Prop 父子组件单向同步 父 -> 子
@Link 父子组件双向同步 父 <-> 子
@Provide/@Consume 跨组件层级双向同步 祖先 <-> 后代
@Local (V2) 组件内部状态管理 (V2) 组件内部
@Param (V2) 父子组件数据传递 (V2) 父 -> 子

✍️ 实战建议

  1. 从V1开始:目前状态管理V1的生态和资料更成熟,建议从V1入手,熟练后再探索V2。

  2. 合理选择:根据数据流向和组件关系,选择合适的装饰器。避免过度使用@Link@Consume,以防数据流变得难以追踪。

  3. 拥抱组合:善用@Styles@Extend@Builder来提炼公共代码,这将显著提升项目的可维护性。

希望这份梳理能帮助你更好地理解和运用鸿蒙开发中的装饰器,让你的开发之旅更加得心应手。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐