ArkTS 模块通信全解析:用事件总线实现页面消息联动

摘要

在 HarmonyOS 的开发过程中,随着项目模块的不断增加,页面与组件之间的直接调用变得不再现实。如何高效、解耦地实现模块间通信,成为了开发者关注的重点。ArkTS 提供了多种方案,其中事件总线是一种简单、轻便、扩展性强的方式,适用于大部分跨模块通信场景。

引言

在日常开发中,我们常常会遇到这样的情况:A 模块的某个动作需要影响 B 模块的状态,但这两个模块又没有直接的父子或引用关系。如果你还在用全局变量、静态方法传值,那其实风险挺大 ------ 不仅维护难度高,而且逻辑容易混乱。为了解耦模块之间的通信,我们可以借助事件总线(EventBus)

事件总线是一种发布-订阅模式,它允许我们在不同组件或模块之间传递消息,而不需要彼此知道对方的存在。

跨模块通信的实现方式

使用事件总线封装通信逻辑

我们先来创建一个全局的事件总线类 EventBus.ts,它是整个通信机制的核心。

ts 复制代码
// EventBus.ts
export class EventBus {
  private static instance: EventBus;
  private events: { [key: string]: Function[] } = {};

  private constructor() {}

  static getInstance() {
    if (!EventBus.instance) {
      EventBus.instance = new EventBus();
    }
    return EventBus.instance;
  }

  on(event: string, callback: Function) {
    if (!this.events[event]) {
      this.events[event] = [];
    }
    this.events[event].push(callback);
  }

  emit(event: string, data?: any) {
    if (this.events[event]) {
      this.events[event].forEach((callback) => callback(data));
    }
  }
}

这个类使用了单例模式,确保事件中心只有一个实例,并通过 on 方法监听事件,通过 emit 方法广播事件。

主页面:发送事件的模块

我们在主页面 MainPage.ets 中使用按钮点击来发送一个事件:

ts 复制代码
// MainPage.ets
import { EventBus } from './EventBus';

@Entry
@Component
struct MainPage {
  build() {
    Column() {
      Button('Send Event')
        .onClick(() => {
          EventBus.getInstance().emit('message', 'Hello from MainPage');
        });
    }.padding(20);
  }
}

点击按钮时,通过 emit 方法发送了一个名为 message 的事件,并携带数据 Hello from MainPage

接收页面:监听并响应事件

在另一个页面 SecondaryPage.ets 中,我们来接收这个事件:

ts 复制代码
// SecondaryPage.ets
import { EventBus } from './EventBus';

@Entry
@Component
struct SecondaryPage {
  private message: string = 'No message yet';

  build() {
    // 注册事件监听器
    EventBus.getInstance().on('message', (data) => {
      this.message = data;
    });

    Column() {
      Text(this.message)
        .fontSize(20);
    }.padding(20);
  }
}

SecondaryPage 中注册了 message 事件的监听器,每当有消息发出时,就会更新页面上的 message

实际应用场景举例

场景一:登录成功后通知首页刷新用户信息

代码示例:

ts 复制代码
// LoginPage.ets
EventBus.getInstance().emit('loginSuccess', { username: '张三' });

// HomePage.ets
EventBus.getInstance().on('loginSuccess', (data) => {
  this.username = data.username;
});

说明:

用户登录成功后不需要手动跳转或回调处理,首页收到 loginSuccess 事件后即可自动更新展示用户名或用户信息。

场景二:设置页面修改主题,通知多个模块更新 UI 风格

代码示例:

ts 复制代码
// SettingsPage.ets
EventBus.getInstance().emit('themeChanged', 'dark');

// AnyPage.ets
EventBus.getInstance().on('themeChanged', (theme) => {
  this.currentTheme = theme;
});

说明:

通过事件总线广播主题变更事件,多个页面只需要注册监听就能自动响应,无需层层传递参数。

场景三:播放器状态通知多个页面同步更新

代码示例:

ts 复制代码
// Player.ets
EventBus.getInstance().emit('playStatus', 'paused');

// FooterWidget.ets / LyricsPage.ets / ControlPanel.ets
EventBus.getInstance().on('playStatus', (status) => {
  this.playStatus = status;
});

说明:

当播放器状态改变后,通过事件总线通知相关组件更新播放图标、歌词状态、控制栏等,做到统一同步更新。

QA 环节

Q1: 为什么不直接使用全局变量或传参来实现?

全局变量虽然方便,但维护困难、安全性差,容易导致模块耦合度过高。事件总线属于发布-订阅模式,发送者和接收者解耦,维护更清晰,扩展性强。

Q2: 如果页面被销毁了,事件监听器还存在吗?

当前实现中,监听器会一直保留在内存中。如果你在组件卸载后不需要再接收事件,建议添加手动移除监听器的功能(可扩展 off 方法)来避免内存泄漏。

Q3: 事件可以传复杂对象吗?

可以,emit(event: string, data: any) 中的 data 可以是字符串、对象、数组甚至函数,只要发送和接收逻辑一致即可。

总结

事件总线是一种非常实用的跨模块通信机制,特别适用于页面之间、组件之间没有直接引用关系时的消息传递。在 ArkTS 的实际开发中,它既轻便,又高效,能大大减少模块之间的耦合,提高代码的可维护性。

如果你在做分布式模块化开发、复杂页面联动,或者需要组件间通信,不妨试试这个思路。

如需后续支持场景(例如带 onceoff 功能的事件总线),也可以继续优化升级。

相关推荐
whysqwhw1 小时前
鸿蒙分布式投屏
harmonyos
whysqwhw2 小时前
鸿蒙AVSession Kit
harmonyos
whysqwhw4 小时前
鸿蒙各种生命周期
harmonyos
whysqwhw5 小时前
鸿蒙音频编码
harmonyos
whysqwhw5 小时前
鸿蒙音频解码
harmonyos
whysqwhw5 小时前
鸿蒙视频解码
harmonyos
whysqwhw6 小时前
鸿蒙视频编码
harmonyos
ajassi20006 小时前
开源 Arkts 鸿蒙应用 开发(十八)通讯--Ble低功耗蓝牙服务器
华为·开源·harmonyos
前端世界7 小时前
在鸿蒙应用中快速接入地图功能:从配置到实战案例全解析
华为·harmonyos
江拥羡橙8 小时前
【基础-判断】HarmonyOS提供了基础的应用加固安全能力,包括混淆、加密和代码签名能力
安全·华为·typescript·harmonyos