一、组件内状态(自己用)

1. @State

  • 响应式变量,改了自动刷新 UI
  • 用于:页面显示、开关、计数、列表

2. @Local

  • 非响应式,改了不刷新 UI
  • 用于:临时数据、缓存、中间计算

二、父子组件通信(最常用!高频!)

3. @Prop

父 → 子 单向传递,子不能改

@Prop name: string;
  • 父传子,只读
  • 场景:标题、配置、静态数据
  • 在鸿蒙 ArkUI 中,@Prop 装饰器用于建立单向数据同步:父组件将数据传递给子组件,子组件可以修改自己的 @Prop 副本,但不会自动同步回父组件。如果子组件需要修改父组件的数据,通常有两种方式:

  • 使用 @Link 装饰器(双向同步)

  • 使用回调函数(通过 @Prop 接收值,再通过事件将修改意图通知父组件)

案例:计数器组件

场景:父组件维护一个 count 状态,子组件展示该值并提供“增加”按钮,点击后父组件的 count 增加。

1. 子组件(CounterChild.ets)
@Component
export struct CounterChild {
  // 接收父组件传入的值(只读)
  @Prop count: number;
  // 定义回调,用于通知父组件增加计数的意图
  onIncrease?: () => void;

  build() {
    Column() {
      Text(`子组件显示计数:${this.count}`)
        .fontSize(20)
        .margin(10)
      Button('增加')
        .onClick(() => {
          // 通过回调通知父组件执行增加操作
          if (this.onIncrease) {
            this.onIncrease();
          }
        })
        .margin(10)
    }
    .width('100%')
    .height(150)
    .backgroundColor('#f0f0f0')
    .borderRadius(8)
  }
}
2. 父组件(ParentPage.ets)
typescript

import { CounterChild } from './CounterChild';

@Entry
@Component
struct ParentPage {
  @State parentCount: number = 0;

  // 子组件触发的回调:修改父组件状态
  private handleIncrease() {
    this.parentCount++;
  }

  build() {
    Column() {
      Text(`父组件计数:${this.parentCount}`)
        .fontSize(24)
        .margin(20)

      // 使用子组件,传递 prop 和回调
      CounterChild({
        count: this.parentCount,
        onIncrease: this.handleIncrease.bind(this)
      })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}
2. 父组件(ParentPage.ets)
import { CounterChild } from './CounterChild';

@Entry
@Component
struct ParentPage {
  @State parentCount: number = 0;

  // 子组件触发的回调:修改父组件状态
  private handleIncrease() {
    this.parentCount++;
  }

  build() {
    Column() {
      Text(`父组件计数:${this.parentCount}`)
        .fontSize(24)
        .margin(20)

      // 使用子组件,传递 prop 和回调
      CounterChild({
        count: this.parentCount,
        onIncrease: this.handleIncrease.bind(this) //方法一
        onIncrease: (()=>{  //方法二
           this.handleIncrease()
        })
      })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

关键点说明

这种方式遵循了单向数据流原则,使数据变化来源清晰,便于维护。

  • 父传子,只读
  • 场景:标题、配置、静态数据
  • 在鸿蒙 ArkUI 中,@Prop 装饰器用于建立单向数据同步:父组件将数据传递给子组件,子组件可以修改自己的 @Prop 副本,但不会自动同步回父组件。如果子组件需要修改父组件的数据,通常有两种方式:

  • 使用回调函数(通过 @Prop 接收值,再通过事件将修改意图通知父组件)

  • @Prop count 让子组件能显示父组件的值,且子组件内部可以修改该副本(但不会影响父组件)。

  • 子组件通过自定义回调 onIncrease 将修改意图传递给父组件。

  • 父组件在回调中更新 @State parentCount,触发 UI 重新渲染,子组件因 @Prop 接收到新值而同步显示。

4. @Link

父 ↔ 子 双向同步

@Link count: number;
  • 子改 = 父也改
  • 场景:开关、表单、弹窗控制

5. @Provide + @Consume

跨多层组件传递(爷 → 孙)

// 父/祖先
@Provide("user") user = { name: "张三" }

// 子孙任意层
@Consume("user") user;
  • 不用一层层传
  • 场景:用户信息、主题、全局配置

三、全局应用状态(整个 APP 共享)

6. @AppStorage

全局持久化状态(内存)

@AppStorage("token") token: string = "";
  • 所有页面共享
  • 改了所有页面同步刷新

7. @StorageLink

持久化到本地(关机还在)

@StorageLink("userId") userId: string = "";
  • 保存在手机本地存储
  • 场景:用户 ID、登录状态、设置

四、UI 渲染 / 性能优化装饰器

8. @Watch

监听状态变化,自动执行函数

@Watch("onCountChange")
@State count: number = 0;

onCountChange() {
  console.log("count变了")
}
  • 监听变量,一变就做事
  • 场景:搜索防抖、数据联动

9. @Builder

自定义 UI 块(复用 UI 片段)

@Builder
itemTitle(title: string) {
  Text(title).fontSize(20)
}
  • 复用 UI,不用写重复代码

10. @Styles / @Extend

样式复用

@Styles
btnStyle() {
  .width(200).height(40)
}

五、生命周期装饰器(构建 / 卸载)

11. @Entry

标记页面入口(只能一个)

12. @Component

标记自定义组件

13. @BuilderParam

组件内传递构建函数


六、最实用总结(背会就能写鸿蒙项目)

数据流动一句话记住:

  • 自己用 → @State(会刷新) / @Local(不刷新)
  • 父传子 → @Prop
  • 父子双向 → @Link
  • 跨多层 → @Provide + @Consume
  • 全局共享 → @AppStorage
  • 本地持久化 → @StorageLink
  • 监听变化 → @Watch
  • 复用 UI → @Builder

七、我给你一个万能速记表(面试直接背)

表格

装饰器 作用 场景
@State 组件内响应式 页面显示数据
@Local 组件内临时变量 缓存 / 计算
@Prop 父→子单向 标题、配置
@Link 父子双向同步 开关、表单
@Provide 祖先跨层传递 用户信息
@Consume 后代跨层接收 页面取值
@AppStorage 全局状态 主题、登录
@StorageLink 本地持久化 用户 ID
@Watch 监听变量变化 搜索、联动
@Builder UI 复用 列表项、按钮
Logo

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

更多推荐