Angular 5手动广播事件:$broadcast/$on替代方案监听异常
我之前也碰到过一模一样的问题!这种情况大概率是你的Broadcaster服务没有保持单例状态——如果两个组件拿到的是服务的不同实例,那自然只有一个能接收到事件通知。下面给你梳理问题原因和解决步骤:
问题核心:服务实例不唯一
如果你的Broadcaster服务在组件的providers数组里声明过,或者没有在根模块正确提供,就会导致每个组件都创建自己的服务实例。这种情况下,父组件在自己的实例上广播事件,两个子组件各自监听自己实例的事件通道,自然只有一个能“听到”。
正确的Broadcaster服务实现(Angular 5适配版)
先把服务改成单例模式,这里用Angular 5支持的方式(Angular 5还没有providedIn: 'root',所以要在根模块注册):
import { Injectable } from '@angular/core'; import { Subject } from 'rxjs/Subject'; import { Observable } from 'rxjs/Observable'; import 'rxjs/add/operator/filter'; import 'rxjs/add/operator/map'; interface BroadcastEvent { key: any; data?: any; } @Injectable() export class BroadcasterService { private _eventSubject = new Subject<BroadcastEvent>(); // 广播事件 broadcast(key: any, data?: any): void { this._eventSubject.next({ key, data }); } // 监听指定key的事件 on<T>(key: any): Observable<T> { return this._eventSubject.asObservable() .filter(event => event.key === key) .map(event => event.data as T); } }
然后在你的AppModule的providers数组里注册这个服务,确保全应用只有一个实例:
import { NgModule } from '@angular/core'; import { BroadcasterService } from './broadcaster.service'; @NgModule({ // ...其他配置 providers: [BroadcasterService] // 根模块注册,保证单例 }) export class AppModule { }
组件端正确使用方式
父组件触发事件
import { Component } from '@angular/core'; import { BroadcasterService } from './broadcaster.service'; @Component({ selector: 'app-parent', template: `<button (click)="notifyChildren()">触发变更事件</button>` }) export class ParentComponent { constructor(private broadcaster: BroadcasterService) {} notifyChildren(): void { // 广播key为"COMPONENT_UPDATE"的事件,携带数据 this.broadcaster.broadcast('COMPONENT_UPDATE', { content: '父组件通知更新' }); } }
子组件监听事件(两个组件写法一致)
以Component1为例:
import { Component, OnInit, OnDestroy } from '@angular/core'; import { BroadcasterService } from './broadcaster.service'; import { Subscription } from 'rxjs/Subscription'; @Component({ selector: 'app-component1', template: `<p>Component1收到的通知:{{ message }}</p>` }) export class Component1Component implements OnInit, OnDestroy { message: string; private _subscription: Subscription; constructor(private broadcaster: BroadcasterService) {} ngOnInit(): void { // 订阅指定key的事件 this._subscription = this.broadcaster.on<any>('COMPONENT_UPDATE') .subscribe(data => { this.message = data.content; // 这里写你的业务处理逻辑 }); } ngOnDestroy(): void { // 一定要取消订阅,避免内存泄漏 this._subscription.unsubscribe(); } }
Component2的写法和Component1完全相同,注意不要在Component1或Component2的@Component装饰器里添加providers: [BroadcasterService],否则会重新创建服务实例。
最后排查点
如果还是只有一个组件能收到事件,检查:
- 有没有在某个组件里提前unsubscribe了事件订阅
- 确认两个子组件都在父组件触发事件时已经完成初始化(比如是否用了
*ngIf导致组件未渲染)
内容的提问来源于stack exchange,提问作者Kaustubh Khare
相关产品推荐
相关产品推荐

