本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新
一、事件总线概述
鸿蒙的EventHub是官方提供的轻量级事件总线组件,主要实现页面组件与Ability之间、不同组件层级间的通信解耦。其核心机制基于发布-订阅模式,支持异步事件传递和跨线程通信,适用于状态更新、数据传递等场景。
二、核心API及方法说明
1. 事件注册(订阅)
// 在Ability或Component中注册事件监听
getContext(this).eventHub.on("EVENT_NAME", (param: any) => {
// 处理事件逻辑
});
- 参数说明:
EVENT_NAME
:自定义事件标识(建议用常量定义)param
:事件携带的参数(支持任意类型)
- 作用:监听指定事件,当事件触发时执行回调
2. 事件触发(发布)
// 在任意可访问eventHub的地方触发事件
getContext(this).eventHub.emit("EVENT_NAME", { data: "value" });
- 参数说明:
- 第一个参数为事件名,需与订阅时一致
- 第二个参数为传递的数据(可选)
- 特点:支持异步触发,不会阻塞当前线程
3. 事件取消订阅
// 移除指定事件的所有监听
getContext(this).eventHub.off("EVENT_NAME");
// 移除单个回调(需保留函数引用)
const handler = (param) => { /* ... */ };
eventHub.on("EVENT_NAME", handler);
eventHub.off("EVENT_NAME", handler);
- 使用场景:页面销毁时需清理事件监听,避免内存泄漏
三、典型使用场景与示例
场景1:跨页面状态同步
案例:登录成功后跳转首页
// 登录页(LoginPage.ets)
aboutToAppear() {
getContext(this).eventHub.on("NAV_HOME", () => {
router.replaceUrl({ url: "pages/HomePage" });
});
}
// 成功页(SuccessPage.ets)
onClick() {
getContext(this).eventHub.emit("NAV_HOME");
}
说明:通过事件解耦页面跳转逻辑,避免直接依赖页面引用。
场景2:组件间数据传递
// 父组件发送数据
eventHub.emit("UPDATE_TITLE", { title: "新标题" });
// 子组件接收
eventHub.on("UPDATE_TITLE", (data) => {
this.title = data.title; // 更新UI
});
优势:替代Prop逐层传递,简化复杂组件通信。
四、高级用法与注意事项
1. 事件优先级控制
虽然EventHub自身未内置优先级,但可通过自定义事件总线实现:
class PriorityEventBus {
private highPriorityListeners: Function[] = [];
private normalListeners: Function[] = [];
emit(event: string, data: any, isHigh = false) {
const listeners = isHigh ? this.highPriorityListeners : this.normalListeners;
listeners.forEach(fn => fn(data));
}
}
应用场景:支付结果、网络状态等关键事件优先处理。
2. 异步事件处理
eventHub.on("ASYNC_TASK", async (data) => {
const result = await fetchData(data.url); // 异步操作
eventHub.emit("TASK_DONE", result);
});
注意:需配合Promise
或async/await
避免阻塞主线程。
3. 内存管理建议
- 在
aboutToDisappear
生命周期中取消订阅 - 避免在循环中频繁创建/销毁事件监听
- 使用
WeakMap
管理大型对象参数
五、官方API扩展对比
组件 | 适用场景 | 特点 |
---|---|---|
EventHub | 页面/组件间通信 | 轻量级,无需额外配置 |
Emitter | 复杂事件系统(如拖拽) | 支持冒泡/捕获机制 |
PostTask | 线程间任务调度 | 基于优先级队列,支持延迟执行 |