You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 00:54:57