Angular组件订阅Subject无法接收值问题求助
问题原因
你的ScrollService虽然配置了providedIn: 'root'(单例模式),但在HeaderComponent和NavigationComponent的@Component装饰器中都添加了providers: [ScrollService],这会导致每个组件都创建独立的ScrollService实例。Header组件发送的事件只会在自身实例中传播,Navigation组件订阅的是另一个实例的Subject,自然收不到消息。
解决步骤
1. 移除组件内的服务声明
删除HeaderComponent和NavigationComponent的@Component配置中的providers: [ScrollService],让两个组件共享根注入器提供的单例服务。
修改后的HeaderComponent:
import { Component, ElementRef, HostListener, ViewChild } from '@angular/core'; import { ScrollService } from '../scroll.service'; @Component({ selector: 'app-header', templateUrl: './header.component.html', styleUrls: ['./header.component.scss'] // 移除providers数组 }) export class HeaderComponent { constructor(private scrollService: ScrollService) {} @ViewChild('titleLogo') titleDiv!: ElementRef; @HostListener('document:scroll', ['$event']) public onViewportScroll() { const windowHeight = window.innerHeight; const titleBoundingRect = this.titleDiv.nativeElement.getBoundingClientRect(); if (titleBoundingRect.top < 0 || titleBoundingRect.bottom > windowHeight) { this.scrollService.titleInView(true); } else { this.scrollService.titleInView(false); } } }
修改后的NavigationComponent:
import { Component, OnInit } from '@angular/core'; import { ScrollService } from '../scroll.service'; @Component({ selector: 'app-navigation', templateUrl: './navigation.component.html', styleUrls: ['./navigation.component.scss'] // 移除providers数组 }) export class NavigationComponent implements OnInit { constructor(private scrollService: ScrollService) { } bodyElement = document.getElementsByTagName('body')[0]; showOverlayMenu: boolean = false; @Input() burgermenu: boolean = false; showName: boolean = false; // 移除@Input,避免父组件值覆盖Service更新的值 ngOnInit(): void { this.scrollService.titleScrolledOut.subscribe((value) => { console.log('showName = :', value); this.showName = value; }); } toggleBurgerMenu() { this.showOverlayMenu = !this.showOverlayMenu; this.bodyElement.style.overflowY = this.showOverlayMenu ? 'hidden' : 'scroll'; } }
2. 可选:换成BehaviorSubject(避免订阅晚错过初始值)
如果Navigation组件可能在Header发送事件之后才初始化,普通Subject会让它错过之前的事件。可以把Subject换成BehaviorSubject,它会保存最新值,新订阅者能立即拿到当前值:
修改后的ScrollService:
import { Injectable } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class ScrollService { // 初始值设为false,可根据需求调整 titleScrolledOut = new BehaviorSubject<boolean>(false); titleInView(value: boolean) { this.titleScrolledOut.next(!value); } constructor() { } }
内容的提问来源于stack exchange,提问作者IngoHe
相关产品推荐
相关产品推荐

