Angular全局功能实现问询:主题切换监听与跨组件搜索联动
问题1:主题状态全局同步实现
你当前的ThemeService用普通属性存状态,没有状态变更通知能力,替换为RxJS的BehaviorSubject即可实现全局监听:
第一步修改ThemeService
import { Injectable } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class ThemeService { // 私有Subject存储状态,禁止外部直接修改 private readonly isLightTheme$ = new BehaviorSubject<boolean>(true); // 对外暴露只读Observable,供所有组件订阅 public readonly isLightThemeObserver$ = this.isLightTheme$.asObservable(); changeTheme(): void { this.isLightTheme$.next(!this.isLightTheme$.value); } }
第二步修改关联组件代码
所有需要用到主题状态的组件都不需要自己维护状态副本,直接订阅服务的流即可:
- 头部组件TS代码
export class HeaderComponent { isLightTheme$ = this.themeService.isLightThemeObserver$; constructor(private themeService: ThemeService) {} changeTheme(): void { this.themeService.changeTheme(); } }
- 头部组件HTML代码,用
AsyncPipe自动订阅/销毁流
<button (click)="changeTheme()"> {{ (isLightTheme$ | async) ? '切换深色主题' : '切换浅色主题' }} </button>
其他需要适配主题的组件,注入ThemeService订阅isLightThemeObserver$就能实时拿到最新主题状态。
问题2:跨组件搜索过滤实现
两个无父子关系的独立组件联动,用公共服务+Observables是最规范的实现方案:
第一步创建SearchService做状态中转
import { Injectable } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class SearchService { private readonly searchKeyword$ = new BehaviorSubject<string>(''); public readonly searchKeywordObserver$ = this.searchKeyword$.asObservable(); updateKeyword(keyword: string): void { this.searchKeyword$.next(keyword.trim().toLowerCase()); } }
第二步搜索输入框组件关联服务
输入框组件TS代码
export class SearchInputComponent { constructor(private searchService: SearchService) {} onInput(e: Event): void { const inputEl = e.target as HTMLInputElement; this.searchService.updateKeyword(inputEl.value); } }
输入框组件HTML代码
<input type="text" placeholder="搜索国家" (input)="onInput($event)">
第三步卡片容器组件实现过滤逻辑
卡片组件TS代码
import { of, combineLatest } from 'rxjs'; import { map } from 'rxjs/operators'; // 替换为你本地的模拟国家数据,后续对接API直接替换成接口返回的Observable即可 const MOCK_COUNTRY_LIST = [ { name: '中国', code: 'CN' }, { name: '美国', code: 'US' } ]; export class CountryCardComponent { // 合并国家列表流和搜索关键词流,自动触发过滤 filteredCountries$ = combineLatest([ of(MOCK_COUNTRY_LIST), this.searchService.searchKeywordObserver$ ]).pipe( map(([countryList, keyword]) => { if (!keyword) return countryList; return countryList.filter(item => item.name.toLowerCase().includes(keyword)); }) ) constructor(private searchService: SearchService) {} }
卡片组件HTML代码
<div class="card-container"> <div class="country-card" *ngFor="let country of filteredCountries$ | async"> {{ country.name }} </div> </div>
注:所有通过AsyncPipe订阅的流不需要手动取消订阅,组件销毁时Angular会自动处理,不会产生内存泄漏
内容的提问来源于stack exchange,提问作者user15773616
相关产品推荐
相关产品推荐

