MST

星途 面试题库

面试题:Angular组件通信之非父子组件通信

对于Angular中没有直接父子关系的组件,比如兄弟组件或隔代组件之间,通常有哪些通信方式?每种方式的原理是什么?请详细说明,并针对其中一种方式给出具体的代码实现示例。
37.5万 热度难度
前端开发Angular

知识考点

AI 面试

面试题答案

一键面试

在Angular中,没有直接父子关系的组件(如兄弟组件或隔代组件)之间的通信方式主要有以下几种:

1. 通过服务(Service)共享数据

  • 原理:创建一个服务,在需要通信的组件中注入该服务。组件通过调用服务的方法来读写数据,从而实现数据共享。因为在整个应用中,注入的服务实例是单例的,所以不同组件可以通过这个单例服务进行通信。
  • 代码示例
    • 创建服务
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class SharedService {
  private data: string;

  setData(value: string) {
    this.data = value;
  }

  getData() {
    return this.data;
  }
}
- **组件1使用服务设置数据**:
import { Component } from '@angular/core';
import { SharedService } from './shared.service';

@Component({
  selector: 'app-component1',
  templateUrl: './component1.html'
})
export class Component1 {
  constructor(private sharedService: SharedService) {}

  sendData() {
    this.sharedService.setData('Hello from Component1');
  }
}
- **组件2使用服务获取数据**:
import { Component } from '@angular/core';
import { SharedService } from './shared.service';

@Component({
  selector: 'app-component2',
  templateUrl: './component2.html'
})
export class Component2 {
  dataFromComponent1: string;
  constructor(private sharedService: SharedService) {
    this.dataFromComponent1 = this.sharedService.getData();
  }
}

2. 使用@Output()EventEmitter结合父组件中转

  • 原理:对于兄弟组件,其中一个兄弟组件通过@Output()装饰器和EventEmitter来发出事件,父组件监听这个事件并接收数据,然后父组件再将数据传递给另一个兄弟组件。对于隔代组件,子组件通过@Output()将事件传递给父组件,父组件再继续向上传递,直到到达一个共同的祖先组件,由这个祖先组件将数据传递给目标隔代组件。
  • 示例说明:假设组件A和组件B是兄弟组件,组件A要向组件B传递数据。组件A使用@Output()EventEmitter发出事件,父组件监听这个事件并获取数据,然后父组件通过属性绑定将数据传递给组件B。

3. RxJS的Subject和BehaviorSubject

  • 原理Subject是RxJS中的一种可观察对象,它可以将值多播给多个观察者。BehaviorSubjectSubject的一种变体,它会保存“当前”值,并将这个值发送给新订阅的观察者。不同组件可以订阅SubjectBehaviorSubject,当有新值发布时,所有订阅者都会收到通知。
  • 代码示例
    • 创建服务并使用BehaviorSubject
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class RxjsService {
  private dataSubject = new BehaviorSubject<string>('initial value');
  data$ = this.dataSubject.asObservable();

  updateData(newValue: string) {
    this.dataSubject.next(newValue);
  }
}
- **组件1使用服务更新数据**:
import { Component } from '@angular/core';
import { RxjsService } from './rxjs.service';

@Component({
  selector: 'app-component1',
  templateUrl: './component1.html'
})
export class Component1 {
  constructor(private rxjsService: RxjsService) {}

  sendData() {
    this.rxjsService.updateData('Data from Component1');
  }
}
- **组件2订阅服务获取数据**:
import { Component } from '@angular/core';
import { RxjsService } from './rxjs.service';

@Component({
  selector: 'app-component2',
  templateUrl: './component2.html'
})
export class Component2 {
  dataFromComponent1: string;
  constructor(private rxjsService: RxjsService) {
    this.rxjsService.data$.subscribe(data => {
      this.dataFromComponent1 = data;
    });
  }
}