3、ArkTS特有语法与装饰器:@Component、@Entry、@State、@Prop、@Link装饰器的使用场景与区别

说实话,刚接触ArkTS的时候,我第一反应是——这不就是TS加了些装饰器吗?

但真正上手做项目后才发现,这些装饰器才是鸿蒙开发的灵魂。它们决定了你的组件怎么组织、数据怎么流动、UI怎么刷新。今天我就把这几个最常用的装饰器掰开揉碎了讲清楚。

3.1 @Component:组件的身份证

每个自定义组件都必须用@Component标记。它告诉编译器:这是一个UI单元。

我个人习惯把组件拆得尽量小。一个页面拆成头部、内容区、底部三个组件,每个组件独立维护。这样改起来不打架。

核心规则:每个@Component只能有一个build()方法。这是组件的入口。

@Component
struct MyHeader {
  build() {
    Text('这是头部')
      .fontSize(20)
  }
}

嗯,这里要注意:组件名必须大写开头。小写会被当成普通函数,编译直接报错。我刚开始就踩过这个坑。

3.2 @Entry:页面的入口标记

@Entry用来标记页面的根组件。一个页面只能有一个@Entry。

说白了,它就是告诉系统:从这个组件开始渲染。没有它,组件就是个零件,没法独立展示。

@Entry
@Component
struct MainPage {
  build() {
    Column() {
      MyHeader()
      MyContent()
    }
  }
}

我记得有一次,同事把@Entry加到了子组件上,结果页面白屏了半天。排查下来才发现是入口标记放错了位置。

3.3 @State:组件的内部状态

@State是用的最多的装饰器。它让变量变成响应式的——变量一变,UI自动刷新。

使用技巧:只有@State修饰的变量变化才会触发UI更新。普通变量改了,UI不会动。

@Component
struct Counter {
  @State count: number = 0

  build() {
    Column() {
      Text(`点击了 ${this.count} 次`)
      Button('点我')
        .onClick(() => {
          this.count++
        })
    }
  }
}

你想想看,如果没有@State,每次点击都要手动调用update方法,那得多麻烦。我在项目中遇到过,有人把状态存在普通变量里,折腾了半天UI就是不刷新。后来改成@State,问题秒解。

避坑指南:我曾经在@State变量上直接修改对象属性,发现UI没反应。后来才明白,@State只监听变量本身的引用变化。修改对象内部属性,引用没变,所以不会触发刷新。正确的做法是重新赋值整个对象。

3.4 @Prop:父子组件的数据传递

@Prop用于父组件向子组件传数据。子组件拿到数据后可以改,但不会影响父组件。

@Component
struct ChildComponent {
  @Prop message: string

  build() {
    Text(this.message)
  }
}

@Entry
@Component
struct ParentComponent {
  @State parentMsg: string = '来自父组件'

  build() {
    ChildComponent({ message: this.parentMsg })
  }
}

这里有个关键点:@Prop的数据是单向的。子组件改了,父组件不知道。为什么这样设计?说白了就是为了数据流清晰,避免乱改。

我在项目中遇到过这样的场景:列表页的每个卡片需要显示不同的数据。用@Prop传进去,每个卡片独立展示,互不干扰。这比用全局变量靠谱多了。

3.5 @Link:父子组件的双向绑定

@Link和@Prop正好相反。子组件改了数据,父组件也会同步更新。

@Component
struct ChildComponent {
  @Link count: number

  build() {
    Button('子组件加一')
      .onClick(() => {
        this.count++
      })
  }
}

@Entry
@Component
struct ParentComponent {
  @State total: number = 0

  build() {
    Column() {
      Text(`总数:${this.total}`)
      ChildComponent({ count: $total })
    }
  }
}

注意看,传参时用了$total而不是this.total。这个美元符号是@Link的固定写法,少了它编译不过。

使用建议:能用@Prop就别用@Link。双向绑定虽然方便,但数据流会变复杂。我一般只在表单编辑、弹窗确认这种需要双向同步的场景才用@Link。

3.6 四个装饰器的对比总结

装饰器 数据流向 使用场景 注意事项
@Component 定义组件 必须搭配struct使用
@Entry 标记页面入口 每个页面只能有一个
@State 组件内部 管理组件自身状态 修改对象属性需重新赋值
@Prop 父→子 父组件传数据给子组件 子组件修改不影响父组件
@Link 双向 父子组件数据同步 传参用$符号

3.7 实际项目中的选择策略

我总结了一套自己的选择逻辑:

  • 组件内部数据:用@State。比如开关状态、输入框内容。
  • 父传子展示:用@Prop。比如列表项的数据。
  • 需要双向同步:用@Link。比如编辑页面的表单。
  • 跨多层传递:考虑用@Provide和@Consume(后面章节会讲),别用@Link层层传。

个人经验:刚开始用ArkTS时,我总喜欢用@Link,觉得方便。后来项目大了,数据流乱成一锅粥。现在我的原则是:默认用@Prop,除非明确需要双向同步才用@Link。这个习惯帮我省了不少调试时间。

好了,这几个装饰器搞明白了,ArkTS的组件化开发就算入门了。下一章我们聊聊@Provide和@Consume,它们能解决跨层级传递的问题。