鸿蒙的组件通信机制

146 阅读3分钟

鸿蒙(HarmonyOS)的组件通信机制基于ArkUI框架,提供了多样化的方案以适应不同场景(如父子组件、跨层级、兄弟组件或跨页面通信)。以下是核心通信方式的分类及详解:


⚙️ 一、父子组件通信

  1. 单向数据传递(父 → 子)​

    • ​**@Prop 装饰器**​

      • 父组件通过 @State 管理数据,子组件通过 @Prop 接收只读副本。
      • 父数据更新时子组件同步刷新,但子组件修改数据仅限本地,不影响父源。
      • 适用场景​:展示型子组件(如文本显示)。
      // 父组件
      @Component struct Parent {
        @State message: string = "Hello";
        build() { Child({ childMsg: this.message }) }
      }
      // 子组件
      @Component struct Child {
        @Prop childMsg: string;  // 只读
        build() { Text(this.childMsg) }
      }
      
  2. 双向数据绑定(父 ↔ 子)​

    • ​**@Link 装饰器**​

      • 父子共享同一数据源,任何一方修改均实时同步。
      • 父组件需用 @State 定义数据,通过 $变量名(如 $count)传递给子组件的 @Link 变量。
      • 适用场景​:表单输入控件(如输入框、开关)。
      // 父组件
      @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 直接消费,无需中间组件传递。
    • 支持双向同步​:后代修改数据会触发祖先状态更新。
    • 适用场景​:主题配置、用户信息等多组件共享的全局状态。
    // 祖先组件
    @Component struct GrandParent {
      @Provide theme: string = "dark";
      build() { Parent() }
    }
    // 后代组件
    @Component struct Child {
      @Consume theme: string;
      build() { Text(`主题:${this.theme}`) }
    }
    

🔄 三、兄弟组件通信

  1. 全局状态管理(AppStorage)​

    • 应用级共享状态存储,数据变化自动同步到所有依赖组件。
    • 适用场景​:用户登录信息、语言设置等简单全局状态。
    // 存储数据
    AppStorage.SetOrCreate('username', 'Alice');
    // 组件A
    @StorageLink('username') username: string = '';
    // 组件B
    @StorageLink('username') currentUser: string = '';
    
  2. 事件总线(EventHub/Emitter)​

    • ​**EventHub**​:通过事件名通信,支持一对多广播。
    • ​**Emitter**​:轻量级事件管理,通过 eventId 标识事件。
    • 适用场景​:解耦的组件间通知(如列表页触发详情页更新)。
    // 初始化EventHub(在Ability中)
    const eventHub = new common.EventHub();
    // 组件A发送事件
    eventHub.emit('update', { data: "New" });
    // 组件B监听事件
    eventHub.on('update', (data) => { ... });
    
  3. 通过父组件中转

    • 父组件通过 @State 管理共享数据,子组件通过 @Prop 或回调函数与父交互。
    • 适用场景​:兄弟组件有共同父组件且逻辑紧密关联。
    // 父组件
    @Component struct Parent {
      @State sharedData: string = '';
      build() {
        Column() {
          ChildA({ onDataChange: (val) => this.sharedData = val }),
          ChildB({ data: this.sharedData })
        }
      }
    }
    

📄 四、跨页面通信

  1. 路由参数传递

    • 使用 router.pushUrl 跳转时携带参数,目标页面通过 router.getParams 获取。
    • 适用场景​:页面跳转时传递ID等简单数据。
    // 页面A传参
    router.pushUrl({ url: 'pages/PageB', params: { id: 123 } });
    // 页面B接收
    @State params: object = router.getParams();
    
  2. 全局状态(AppStorage)​

    • 数据存储在应用级,跨页面共享且响应式更新。

🧩 五、复杂对象同步

  • ​**@ObjectLink + @Observed**​

    • @Observed 标记数据类,子组件通过 @ObjectLink 绑定对象实例,修改属性触发UI更新。
    • 适用场景​:嵌套对象或数组的同步(如编辑用户资料)。
    @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**​对象属性同步复杂对象监听嵌套对象编辑⭐⭐⭐

💎 最佳实践建议

  1. 父子组件​:

    • 单向数据流 → @Prop
    • 双向绑定 → @Link
  2. 跨层级共享​:

    • 优先 @Provide/@Consume,避免逐层传递。
  3. 兄弟组件​:

    • 解耦场景 → EventHub
    • 紧密耦合 → 父组件中转
    • 全局状态 → AppStorage
  4. 跨页面​:

    • 简单参数 → 路由传参
    • 复杂共享 → AppStorage
  5. 性能敏感场景​:

    • 避免过度使用 AppStorage(中性能影响),优先选择装饰器方案。

更多实践案例可参考鸿蒙官方文档或技术博客(如 CSDN)。