鸿蒙(HarmonyOS)的组件通信机制基于ArkUI框架,提供了多样化的方案以适应不同场景(如父子组件、跨层级、兄弟组件或跨页面通信)。以下是核心通信方式的分类及详解:
⚙️ 一、父子组件通信
-
单向数据传递(父 → 子)
-
**
@Prop
装饰器**- 父组件通过
@State
管理数据,子组件通过@Prop
接收只读副本。 - 父数据更新时子组件同步刷新,但子组件修改数据仅限本地,不影响父源。
- 适用场景:展示型子组件(如文本显示)。
less// 父组件 @Component struct Parent { @State message: string = "Hello"; build() { Child({ childMsg: this.message }) } } // 子组件 @Component struct Child { @Prop childMsg: string; // 只读 build() { Text(this.childMsg) } }
- 父组件通过
-
-
双向数据绑定(父 ↔ 子)
-
**
@Link
装饰器**- 父子共享同一数据源,任何一方修改均实时同步。
- 父组件需用
@State
定义数据,通过$变量名
(如$count
)传递给子组件的@Link
变量。 - 适用场景:表单输入控件(如输入框、开关)。
less// 父组件 @Component struct Parent { @State count: number = 0; build() { Child({ count: $count }) } } // 子组件 @Component struct Child { @Link count: number; build() { Button('+1').onClick(() => this.count++) } }
-
🌐 二、跨层级通信(祖先 → 后代)
-
**
@Provide
和@Consume
装饰器**- 祖先组件通过
@Provide
暴露数据,后代组件通过@Consume
直接消费,无需中间组件传递。 - 支持双向同步:后代修改数据会触发祖先状态更新。
- 适用场景:主题配置、用户信息等多组件共享的全局状态。
scss// 祖先组件 @Component struct GrandParent { @Provide theme: string = "dark"; build() { Parent() } } // 后代组件 @Component struct Child { @Consume theme: string; build() { Text(`主题:${this.theme}`) } }
- 祖先组件通过
🔄 三、兄弟组件通信
-
全局状态管理(
AppStorage
)- 应用级共享状态存储,数据变化自动同步到所有依赖组件。
- 适用场景:用户登录信息、语言设置等简单全局状态。
scss// 存储数据 AppStorage.SetOrCreate('username', 'Alice'); // 组件A @StorageLink('username') username: string = ''; // 组件B @StorageLink('username') currentUser: string = '';
-
事件总线(
EventHub
/Emitter
)- **
EventHub
**:通过事件名通信,支持一对多广播。 - **
Emitter
**:轻量级事件管理,通过eventId
标识事件。 - 适用场景:解耦的组件间通知(如列表页触发详情页更新)。
javascript// 初始化EventHub(在Ability中) const eventHub = new common.EventHub(); // 组件A发送事件 eventHub.emit('update', { data: "New" }); // 组件B监听事件 eventHub.on('update', (data) => { ... });
- **
-
通过父组件中转
- 父组件通过
@State
管理共享数据,子组件通过@Prop
或回调函数与父交互。 - 适用场景:兄弟组件有共同父组件且逻辑紧密关联。
scss// 父组件 @Component struct Parent { @State sharedData: string = ''; build() { Column() { ChildA({ onDataChange: (val) => this.sharedData = val }), ChildB({ data: this.sharedData }) } } }
- 父组件通过
📄 四、跨页面通信
-
路由参数传递
- 使用
router.pushUrl
跳转时携带参数,目标页面通过router.getParams
获取。 - 适用场景:页面跳转时传递ID等简单数据。
css// 页面A传参 router.pushUrl({ url: 'pages/PageB', params: { id: 123 } }); // 页面B接收 @State params: object = router.getParams();
- 使用
-
全局状态(
AppStorage
)- 数据存储在应用级,跨页面共享且响应式更新。
🧩 五、复杂对象同步
-
**
@ObjectLink
+@Observed
**- 用
@Observed
标记数据类,子组件通过@ObjectLink
绑定对象实例,修改属性触发UI更新。 - 适用场景:嵌套对象或数组的同步(如编辑用户资料)。
less@Observed class User { name: string = ''; } // 父组件 @Component struct Parent { @State user: User = new User(); build() { Child({ user: this.user }) } } // 子组件 @Component struct Child { @ObjectLink user: User; build() { TextInput({ text: this.user.name }) } }
- 用
📊 通信方式对比与选型建议
方式 | 数据流向 | 核心机制 | 适用场景 | 复杂度 |
---|---|---|---|---|
**@Prop ** |
父 → 子(单向) | 状态装饰器 | 展示型子组件 | ⭐☆☆ |
**@Link ** |
父 ↔ 子(双向) | 状态装饰器 + $ 语法 |
表单控件双向同步 | ⭐⭐☆ |
**@Provide/@Consume ** |
跨层级双向 | 依赖注入 | 主题/用户信息等全局状态 | ⭐⭐☆ |
**AppStorage ** |
全局双向 | 应用级存储 | 简单全局状态(如用户信息) | ⭐☆☆ |
**EventHub /Emitter ** |
任意方向 | 事件总线 | 解耦通信、一对多通知 | ⭐⭐☆ |
路由传参 | 页面间单向 | URL 参数 | 页面跳转时传递ID | ⭐☆☆ |
**@ObjectLink ** |
对象属性同步 | 复杂对象监听 | 嵌套对象编辑 | ⭐⭐⭐ |
💎 最佳实践建议
-
父子组件:
- 单向数据流 →
@Prop
- 双向绑定 →
@Link
- 单向数据流 →
-
跨层级共享:
- 优先
@Provide/@Consume
,避免逐层传递。
- 优先
-
兄弟组件:
- 解耦场景 →
EventHub
- 紧密耦合 → 父组件中转
- 全局状态 →
AppStorage
- 解耦场景 →
-
跨页面:
- 简单参数 → 路由传参
- 复杂共享 →
AppStorage
-
性能敏感场景:
- 避免过度使用
AppStorage
(中性能影响),优先选择装饰器方案。
- 避免过度使用
更多实践案例可参考鸿蒙官方文档或技术博客(如 CSDN)。