鸿蒙HarmonyOS ArkUI 状态管理装饰器详解
在鸿蒙(HarmonyOS)的 ArkUI 框架中,状态管理装饰器是实现数据与 UI 联动的核心,确保数据变化时 UI 自动更新。
以下是按功能分类的所有常用装饰器,包含作用说明、使用场景及示例代码。
装饰器选择表
| 装饰器组合 / 类型 | 作用域 | 数据流向 | 适用场景 |
|---|---|---|---|
@State | 组件内部 | 单向(数据→UI) | 组件私有状态 |
@State + @Link | 父子组件 | 双向(父↔子) | 父子组件共同修改同一状态 |
@State + @Prop | 父子组件 | 单向(父→子) | 子组件仅展示父组件数据 |
@BuilderParam | 父子组件 | 父→子(UI 片段) | 子组件灵活定制 UI |
@Event | 父子组件 | 子→父(事件 + 数据) | 子组件向父组件反馈操作 |
@Provide + @Consume | 跨层级组件 | 双向(祖先↔后代) | 深层嵌套组件共享状态 |
@StorageLink | 全应用 | 双向(组件↔AppStorage) | 全应用共享状态(如用户信息) |
@StorageProp | 全应用 | 单向(AppStorage→组件) | 仅读取全局状态,不修改 |
@LocalStorageLink | 当前页面 | 双向(组件↔LocalStorage) | 页面内组件共享状态 |
@Observed + @ObjectLink | 组件内部 / 跨组件 | 双向(对象属性→UI) | 监听复杂对象内部属性变化 |
一、组件内部状态装饰器
用于管理组件自身的私有状态,仅在当前组件内部生效。
1. @State
- 作用:最基础的响应式状态装饰器,标记组件内部私有变量。变量值变化时,依赖它的 UI 会自动刷新。
- 适用场景:组件内部独立状态(如计数器、开关状态)。
- 示例:
@State count: number = 0; // 组件内部状态,修改时触发UI更新
build() {Button(\`点击次数: \${this.count}\`).onClick(() => this.count++); // 修改状态,UI自动刷新
}
2. @Link(局部双向绑定)
- 作用:子组件接收父组件的
@State变量,建立双向绑定。子组件修改会同步到父组件,反之亦然。 - 适用场景:父子组件需要共同修改同一状态(如表单输入、滑块值)。
- 使用规则:父组件传递时需用
$符号包裹变量,子组件用@Link接收。 - 示例:
// 子组件
@Component
struct ChildComponent {@Link childCount: number; // 双向绑定父组件状态build() {Button(\`子组件计数: \${this.childCount}\`).onClick(() => this.childCount++); // 修改会同步到父组件}
}```// 父组件
@Entry
@Component
struct ParentComponent {@State count: number = 0;build() {ChildComponent(childCount = \$count) // 传递时加\$}
}
```ts
### 3. `@Prop`(单向绑定)
* **作用**:子组件接收父组件的`@State`变量,仅支持单向同步。父组件修改时子组件更新,子组件修改不影响父组件。
* **适用场景**:子组件仅展示数据、不修改(如展示标题、状态文本)。
* **示例**:
// 子组件
@Component
struct ChildComponent {@Prop childText: string; // 单向接收父组件数据build() {Text(this.childText); // 仅展示,修改无效}
}
// 父组件
@Entry
@Component
struct ParentComponent {@State message: string = "Hello";build() {Column() {ChildComponent(childText = this.message) // 单向传递Button("修改父组件文本").onClick(() => this.message = "Welcome"); // 子组件会同步更新}}
}
二、父子组件通信装饰器
用于父组件向子组件传递数据或 UI 片段,或子组件向父组件发送事件。
4. @BuilderParam
- 作用:父组件向子组件传递 UI 片段(
@Builder定义),允许子组件动态渲染父组件定制的 UI。 - 适用场景:自定义组件需要灵活定制部分 UI(如列表项操作按钮、弹窗内容)。
- 示例:
// 子组件
@Component
struct ChildComponent {@BuilderParam renderItem: () => void; // 接收父组件传递的UI片段build() {Column() {Text("子组件固定内容")this.renderItem(); // 渲染父组件传递的UI}}
}// 父组件
@Entry
@Component
struct ParentComponent {// 定义UI片段@Builder customBuilder() {Button("父组件定制的按钮").backgroundColor(Color.Blue);}build() {ChildComponent(renderItem = this.customBuilder) // 传递UI片段}
}
5. @Event
-
作用:子组件定义事件,父组件通过回调函数接收子组件传递的数据(类似自定义事件)。
-
适用场景:子组件需要向父组件反馈操作结果(如按钮点击、表单提交)。
-
示例:
// 子组件
@Component
struct ChildComponent {@Event onAdd: (value: number) => void; // 定义事件,接收number类型参数build() {Button("子组件触发事件").onClick(() => this.onAdd(1)); // 触发事件并传递参数}
}// 父组件
@Entry
@Component
struct ParentComponent {@State count: number = 0;build() {Column() {Text(\`父组件计数: \${this.count}\`)// 接收子组件事件并处理ChildComponent(onAdd = (val) => this.count += val)}}
}
三、跨组件共享状态装饰器
用于多个无直接父子关系的组件共享状态(全局或局部共享)。
6. @Provide / @Consume(跨层级共享)
- 作用:一对配合使用的装饰器,实现跨层级组件数据共享(无需逐层传递)。
@Provide:在祖先组件声明 “提供” 的状态变量。@Consume:在后代组件声明 “消费” 该状态变量,自动与@Provide关联。
- 适用场景:祖孙组件、深层嵌套组件间的状态共享(如主题切换、用户登录状态)。
- 示例:
// 祖先组件(提供状态)
@Entry
@Component
struct GrandparentComponent {@Provide theme: string = "light"; // 提供跨层级共享的状态build() {ParentComponent(); // 中间层级无需传递}
}
// 父组件(中间层级,无需处理状态)
@Component
struct ParentComponent {build() {ChildComponent();}
}// 后代组件(消费状态)
@Component
struct ChildComponent {@Consume theme: string; // 直接消费祖先组件的状态build() {Text(\`当前主题: \${this.theme}\`)Button("切换主题").onClick(() => this.theme = this.theme === "light" ? "dark" : "light");}
}
7. @StorageLink / @StorageProp(应用级存储)
- 作用:与应用级存储(
AppStorage)关联,实现全应用范围内的状态共享。@StorageLink:双向绑定,修改时同步到AppStorage,并通知所有关联组件。@StorageProp:单向绑定,仅同步AppStorage的数据,修改不反向影响存储。
- 适用场景:全应用共享状态(如用户信息、系统设置、全局通知)。
- 示例:
// 组件A(修改存储)
@Entry
@Component
struct ComponentA {// 双向绑定AppStorage中的userName字段,默认值为空@StorageLink('userName') name: string = '';build() {Input({ value: this.name, placeholder: "输入用户名" }).onChange((val) => this.name = val); // 修改同步到AppStorage}
}// 组件B(读取存储)
@Component
struct ComponentB {// 单向绑定AppStorage中的userName字段@StorageProp('userName') displayName: string = 'Guest';build() {Text(\`欢迎: \${this.displayName}\`); // 自动同步AppStorage的变化}
}
8. @LocalStorageLink / @LocalStorageProp(页面级存储)
- 作用:与页面级存储(
LocalStorage)关联,仅在当前页面的组件间共享状态。 - 适用场景:同一页面内多个组件共享状态(如页面内的表单数据、分页信息)。
- 示例:
// 页面级存储初始化(通常在入口组件)
const pageStorage = new LocalStorage({ count: 0 });
// 组件1(修改页面存储)
@Component
struct PageComponent1 {@LocalStorageLink('count', pageStorage) pageCount: number = 0;build() {Button(\`组件1计数: \${this.pageCount}\`).onClick(() => this.pageCount++);}
}// 组件2(读取页面存储)
@Component
struct PageComponent2 {@LocalStorageProp('count', pageStorage) showCount: number = 0;build() {Text(\`组件2显示: \${this.showCount}\`);}
}// 入口组件
@Entry(localStorage = pageStorage)
@Component
struct PageEntry {build() {Column() {PageComponent1()PageComponent2()}}
}
四、其他特殊状态装饰器
9. @ObjectLink
- 作用:监听引用类型变量(如 class 实例)的内部属性变化,触发 UI 更新。
- 依赖:需配合
@Observed装饰器使用(标记 class 为可观察)。 - 适用场景:需要监听复杂对象内部属性变化(如用户信息对象、配置对象)。
- 示例:
// 标记class为可观察
@Observed
class User {name: string = '';age: number = 0;
}@Component
struct UserComponent {@ObjectLink user: User; // 监听User实例的内部属性变化build() {Column() {Text(\`姓名: \${this.user.name}\`)Text(\`年龄: \${this.user.age}\`)}}
}@Entry
@Component
struct ParentComponent {@State currentUser: User = new User();build() {Column() {UserComponent(user = this.currentUser)Button("修改用户信息").onClick(() => {this.currentUser.name = "张三";this.currentUser.age = 25; // 内部属性变化,UI自动更新})}}
}
10. @Observed
-
作用:装饰 class,标记该类的实例为 “可观察对象”,使其内部属性变化能被
@ObjectLink或@Prop(引用类型)感知。 -
注意:仅修饰 class,不直接用于变量,需与
@ObjectLink配合使用。
