使用 RXJS Subject 轻松解决非父子组件传值问题

Angular 介绍了父组件给子组件传值的方法:

  1. 通过输入型绑定把数据从父组件传到子组件

    子组件使用 @Input 装饰器接受父组件的数据。

  2. 父组件与子组件通过本地变量互动

    父组件不能使用数据绑定来读取子组件的属性或调用子组件的方法。但可以在父组件模板里,新建一个本地变量来代表子组件,然后利用这个变量来读取子组件的属性和调用子组件的方法

另有通过 setter 截听输入属性值的变化,和 ngOnChanges() 来截听输入属性值的变化等方式。

也介绍了子组件给父组件传值的方法:

  1. 父组件监听子组件的事件

    子组件暴露一个 EventEmitter 属性,当事件发生时,子组件利用该属性 emits (向上弹射)事件。父组件绑定到这个事件属性,并在事件发生时作出回应。

  2. 父组件调用@ViewChild()

    可以把子组件作为 ViewChild,注入到父组件里面。

也介绍了父组件和子组件通过服务来通讯。

受此启发,没有父子关系的两个组件之间可以也可以通过服务来通讯。

思路是:

  1. 新建一个服务,实例化一个 Subject 对象 Subject
  2. 在该服务类中,设置输入属性 get,返回 Subject 对象的 Observable
  3. 在该服务类中,设置输出属性 set,将接收到的值通过 Observable 对象的 next 方法发送出去。
  4. 需要传递值的组件中,调用 set 方法。
  5. 需要接收值的组件中,调用 get 方法获取到值。

具体的业务如下:

  • 现有父组件 QaComponent,子组件 ListComponent(问答列表),子组件 RecommendProblemComponent(推荐问题)。
  • 点击推荐问题的问题项,该项作为问题,在问答列表组件中调用接口获取答案展示。

按照以前的思路现将 RecommendProblemComponent 的问题 emits 发射给父组件,父组件接收到后使用 @Input() 属性绑定到 ListComponent,两步,不利于扩展和维护。

现在使用服务通讯的方法,一步完成。使用 Angular 核心代码如下:

  1. 新建一个服务 QaService,设置输入输出属性,设置和发送值。

QaService

private s = new Subject<any>();

/**
 * 推荐问题组件中的问题传递
 * @param question: string
 */
setQuestion(question: string) {
  this.s.next(question);
}

getQuestion(): Observable<string> {
  return this.s.asObservable();
}

RecommendProblemComponent 发送问题:

<section class="recommend-container">
  <h3>推荐问题</h3>
  <ul>
    <li *ngFor="let item of data" (click)="selectQuestion(item)" title="{{ item }}">{{ item }}</li>
  </ul>
</section>
/**
 * @param question: string
 * @description 选择问题,用于提问的备用问题
 */
selectQuestion(question: string): void {
  this.qaService.setQuestion(question);
}

ListComponent 接收问题:

// 接收推荐问题作为问题,重新请求
this.qaService.getQuestion().subscribe((res: string) => {
  const param: QARequestParams = {
    question: res
  };
  this.getQuestion(param);  // 请求接口,获取答案
});
上一篇:Note 3: Commonly used question sentences


下一篇:H - 二分+交互 Gym - 101375H