环境
node 10.15.0
ionic 4.12.0
cordova 9.0
# platforms
cordova-android:8.0.0
cordova-ios: 5.0.0
前言:
AngularJs 中,我们可以使用on来发出、监听广播,实现全局的消息/事件通信;在Angular2+版本,取消了广播功能。
下面我们将使用RxJS的特性来实现事件总线。
注:代码源自ng-event-bus
用法
第一步
导入
# app.module.ts
providers: [
NgEventBus
]
注入
# some component
constructor(private eventBus: NgEventBus){...}
第二步
发送事件
this.eventBus.cast('test:start', {data: 'hahaha'});
第三步
接收事件
# 接收单个
this.eventBus.on('test:start').subscribe((message) => {
console.log(message);
});
# 接收test下所有
this.eventBus.on('test:**').subscribe((message) => {
console.log(message);
});
源码分析
事件定义
interface EventBusMessage {
key: string;
data?: any;
}
this._eventBus 用于收发事件。
此处为何使用Subject?
什么是Subject(主题)?RxJS Subject是一种特殊类型的Observable,允许将值多播到多个观察者Observer。虽然普通的Observable是单播的(每个订阅的Observer都拥有Observable的独立执行),但Subject是多播的。
每个Subject都是一个Observer。它是一个含有next(v),error(e)和complete()的对象。要向Subject提供新值,只需调用next(theValue),它将被多播到已注册接受该Subject的观察者。
constructor() {
this._eventBus = new Subject<EventBusMessage>();
}
发送事件
如Subject的定义,只需调用next方法,就可已广播到所有订阅此Subject的观察者。
public send(key: string, data?: any): void {
if (typeof key !== 'string' || !key.length) {
throw Error('key must be a string and mustn\'t be empty.');
}
this._eventBus.next({key, data});
}
接收事件
参数:事件key
filter:过滤key
此处涉及到key匹配,下面单独说明
public on<T>(key: string): Observable<T> {
return this._eventBus.asObservable().pipe(
filter((event: EventBusMessage): event is EventBusMessage => this.keyMatch(event.key, key)),
map(event => <T>event.data)
);
}
key匹配
具体分析将以注释的形式展现
public keyMatch(key: string, wildcard: string): boolean {
const w = '*';
const ww = '**';
const partMatch = (wl, k) => {
return (wl === w) || (wl === k);
};
const sep = this.separator;
// 以*分割key etc: [app, start]
const kArr = key.split(sep);
// 监听key分割 etc: [app,**]
const wArr = wildcard.split(sep);
const kLen = kArr.length;
const wLen = wArr.length;
const max = Math.max(kLen, wLen);
for (let i = 0; i < max; i++) {
const cK = kArr[i];
const cW = wArr[i];
// 若:后匹配上** && :前不为undefined 则匹配上
if (cW === ww && (typeof cK !== 'undefined')) {
return true;
}
// :前后匹配, 2部分均不同 匹配失败
if (!partMatch(cW, cK)) {
return false;
}
}
return true;
}
下一篇将介绍RxJS的订阅管理。