RxBus与Angular
引言
笔者在参与Angular项目开发过程中常遇到需要解决组件之间、父子页之间的通信问题,为了降低通信复杂度,以及联想到此前参与过的Android项目开发经验,考虑引进事件总线的解决方案,而由于Angular自带RxJS,故开发一个基于RxJS版本的RxBus成为首选。
RxBus
RxBus的核心思想是基于Rx实现的事件发布与订阅,网上有许多相关资料,笔者这里就不做详细介绍,下面是笔者根据RxBus核心思想用ts语言编写的RxBus源代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49import { Subject, Observable } from 'rxjs';
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class RxBus {
bus: Subject<any> = new Subject();
subjectMapper: {
[propName: string]: Array<Subject<any>>;
} = {};
toObserverable(): Observable<any> {
return this.bus;
}
send(object: any) {
this.bus.next(object);
}
register<T>(tag: any): Observable<T> {
const subject = new Subject<T>();
let subjectList = this.subjectMapper[tag];
if (subjectList == null) {
subjectList = new Array<Subject<T>>();
this.subjectMapper[tag] = subjectList;
}
subjectList.push(subject);
return subject;
}
unregister(tag: any, observable: Observable<any>) {
const subjectList = this.subjectMapper[tag];
if (subjectList != null) {
this.subjectMapper[tag] = subjectList.filter(subject => subject !== observable);
if (this.subjectMapper[tag].length === 0) {
delete this.subjectMapper[tag];
}
}
}
post<T>(tag: any, object: T) {
const subjectList = this.subjectMapper[tag];
if (subjectList != null) {
subjectList.forEach(subject => subject.next(object));
}
}
}
如何使用
笔者以iframe子页调用父页Angular生命周期中的函数为例加以说明
在Angular应用启动时,将RxBus事件总线加入到window全局变量中,便于iframe子页以top.window.rxbus的形式调用
1
2
3
4
5
6
7
8
9//app.component.ts
...
//通过构造函数注入RxBus事件总线
constructor(public rxbus: RxBus, private ngZone: NgZone, ...) {
...
(window as any).rxbus = this.rxbus;
...
}
...在RxBus中注册事件并订阅
1
2
3
4
5
6
7
8...
this.rxbus.register<any>('graph').subscribe(data => {
//需要通过NgZone将调用作用域加入到Angular生命周期中
this.ngZone.run(() => {
...
});
});
...在iframe子页中发布事件
1
2
3
4
5
6
7
8...
top.window.rxbus.post('graph', {
tag: '',
payload: {
}
});
...
通过事件传递的数据结构开发者可以根据实际情况自行约定