使用rxjs管理页面事件流

在后台系统,以及数据系统中,一个区域内经常包含多个输入框,按钮等等操作,分别控制页面内的不同功能。往往我们在注册事件的回调中发起请求,这样的方式将导致以下问题:

​ 1. 事件回调函数承担责任较多,有时需要联动其他条件,触发更新数据,同时还要在回调中处理自身数据问题。

​ 2.事件管理不清晰,当多个条件同时变更,存在联动等情况下处理过于复杂,扩展性交差。

​ 3.http请求效率问题,同上文中http请求问题。

image-20201119162918178

我们可以把每个输入的可变化值看成是一个流,代码中用subject来实现,功能重复的流可以聚合成为同一个流,供后续使用。

image-20201119165406487

代码实现如下:

 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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
@Component({
  selector: 'app-event-stream',
  template: `
    <div><label>label:1 修改我tableData:1234都更新</label><input type=”nbumber“ [(ngModel)]="str1" (ngModelChange)="input1$.next($event)"></div>
    <div><label>label:2 修改我tableData:234都更新</label><input type=”nbumber“ [(ngModel)]="str2" (ngModelChange)="input2$.next($event)"></div>
    <div><label>label:3 修改我tableData:34都更新</label><input type=”nbumber“ [(ngModel)]="str3" (ngModelChange)="input3$.next($event)"></div>
    <div><label>label:4 修改我tableData:4更新</label><input type=”nbumber“ [(ngModel)]="str4" (ngModelChange)="input4$.next($event)"></div>
    <p>table1Data: {{table1Data}}</p>
    <p>table2Data: {{table2Data}}</p>
    <p>table3Data: {{table3Data}}</p>
    <p>table4Data: {{table4Data}}</p>
  `,
  styleUrls: ['./event-stream.component.scss']
})
export class EventStreamComponent implements OnInit {

  // 分别对应页面输入事件流
  input1$ = new BehaviorSubject('');
  input2$ = new BehaviorSubject('');
  input3$ = new BehaviorSubject('');
  input4$ = new BehaviorSubject('');

  // 分别对应页面输入值
  str1 = '';
  str2 = '';
  str3 = '';
  str4 = '';

  // 分别对应页面数据展示
  table1Data?;
  table2Data?;
  table3Data?;
  table4Data?;


  table4$: Observable<string>;
  table3$: Observable<string>;
  table2$: Observable<string>;
  table1$: Observable<string>;

  getTableData(strs: string[]) {
    return of(strs.reduce((accumulator, currentValue) => accumulator + '+' + currentValue));
  }

  constructor() { }

  private pipeCommonInput<T>(ob: Observable<T>): Observable<T> {
    return ob.pipe(
      debounceTime(300),
      distinctUntilChanged(),
    );
  }

  ngOnInit(): void {
    // table4数据订阅
    this.table4$ = this.pipeCommonInput(this.input4$);
    this.table3$ = this.pipeCommonInput(merge(this.input4$, this.input3$));
    this.table2$ = this.pipeCommonInput(merge(this.input4$, this.input3$, this.input2$));
    this.table1$ = this.pipeCommonInput(merge(this.input4$, this.input3$, this.input2$, this.input1$));

    this.table4$
    .pipe(switchMap(() => this.getTableData([this.str4])))
    .subscribe(res => {
      this.table4Data = res;
    });
    this.table3$
    .pipe(switchMap(() => this.getTableData([this.str4, this.str3])))
    .subscribe(res => {
      this.table3Data = res;
    });
    this.table2$
    .pipe(switchMap(() => this.getTableData([this.str4, this.str3, this.str2])))
    .subscribe(res => {
      this.table2Data = res;
    });
    this.table1$
    .pipe(switchMap(() => this.getTableData([this.str4, this.str3, this.str2, this.str1])))
    .subscribe(res => {
      this.table1Data = res;
    });
  }
}