Angular 5 + RxJS:非父子组件间点击触发函数问题求助
问题根源与解决方案
你遇到的这个问题其实很典型:两个组件使用的是EventProxyService的不同实例,所以Component1触发的事件根本传不到Component2那里。
为什么会出现这种情况?
因为你在Component1和Component2的@Component装饰器里都加了providers: [ EventProxyService ]——按照Angular的依赖注入规则,只要在组件级别声明了服务提供者,每个组件都会生成一个该服务的独立实例。这就导致Component1调用的是自己专属的服务实例,而Component2订阅的是另一个完全无关的实例,自然收不到事件。
怎么解决?
要实现组件间通过服务通信,必须让服务成为全局单例,确保所有组件共享同一个服务实例。有两种推荐的实现方式:
方式1:用providedIn: 'root'(Angular 6+ 首选)
直接在服务的@Injectable装饰器里配置,让Angular自动把服务注册为根级单例:
import { Injectable } from '@angular/core'; import { Observable, Subject } from 'rxjs'; // RxJS 6+的正确导入路径 @Injectable({ providedIn: 'root' // 关键配置:让服务成为全局单例 }) export class EventProxyService { private dataSource = new Subject<any>(); data$ = this.dataSource.asObservable(); change(param: any) { console.log("in service", param); this.dataSource.next(param); } }
方式2:在根模块的providers里注册服务
如果是Angular 6之前的版本,可以在AppModule的providers数组里添加服务:
// app.module.ts import { NgModule } from '@angular/core'; import { EventProxyService } from './event-proxy.service'; @NgModule({ providers: [EventProxyService] // 在根模块注册,确保全局只有一个实例 }) export class AppModule { }
最后修正组件代码
无论用哪种方式,都要删掉两个组件@Component装饰器里的providers: [ EventProxyService ],这样组件才会从根注入器获取单例服务:
Component1 修正后:
import { EventProxyService } from './event-proxy.service'; @Component({ selector: 'app-component1', template: `<button (click)="onClick()">Trigger Event</button>` // 移除了 providers 数组 }) export class Component1 { constructor(private eventProxyService: EventProxyService){} onClick(){ console.log("onClick clicked"); this.eventProxyService.change("1"); } }
Component2 修正后:
import { EventProxyService } from './event-proxy.service'; import { OnInit } from '@angular/core'; @Component({ selector: 'app-component2' // 移除了 providers 数组 }) export class Component2 implements OnInit { constructor(private eventProxyService: EventProxyService){} ngOnInit() { this.eventProxyService.data$.subscribe((param: any) => { console.log("in jobs", param); }); } }
额外提示
如果你的RxJS版本是6及以上,一定要注意Observable和Subject的导入路径是rxjs,而不是旧版本的rxjs/Observable或rxjs/Subject,否则会出现编译错误。
这样修改后,当你点击Component1的按钮时,Component2的订阅就能正常接收到参数了!
内容的提问来源于stack exchange,提问作者Ken Spencer
相关产品推荐
相关产品推荐

