Angular 15路由复用组件时如何重置组件状态
解决方案:Angular 15降临日历组件状态重置/缓存问题
问题原因
Angular路由切换同组件(如CalendarComponent)时,默认复用组件实例,导致子组件WindowComponent的isOpen状态不会自动重置。当年份切换后,相同日期的窗口会继承之前年份的打开状态。
以下提供两种可行方案,按需选择:
方案一:重置组件状态(简单直接)
当年份切换时,自动重置所有窗口的打开状态,回到初始未打开状态。
实现步骤
- 修改
WindowComponent,添加ngOnChanges钩子监听年份变化:
import { Component, Input, OnChanges, SimpleChanges } from '@angular/core'; // ...其他导入 @Component({ selector: 'aoc-window', templateUrl: './window.component.html', styleUrls: ['./window.component.scss'] }) export class WindowComponent implements OnChanges { @Input() year: number = 0; @Input() day: number = 0; aocResponse?: AOCResponse | undefined; isOpen: boolean = false; constructor(private aocService: WindowService) { } // 监听输入属性变化 ngOnChanges(changes: SimpleChanges) { // 当year参数变化时,重置窗口状态 if (changes['year'] && !changes['year'].firstChange) { this.isOpen = false; this.aocResponse = undefined; } } open() { this.isOpen = true; this.getAOCResponse(); } getAOCResponse() { const callPath = `${environment.aocPath}/${this.year}/${this.day}`; this.aocService.getAOCAnswer(callPath) .subscribe(aocResponse => { this.aocResponse = aocResponse; }, error => { console.error(error); this.aocResponse = { answer: 'Failed' } }); } }
- (可选)强制重建
CalendarComponent
如果希望彻底重建整个组件树,可修改路由配置:
// app-routing.module.ts const routes: Routes = [ // ...其他路由 { path: 'calendar/:year', component: CalendarComponent, runGuardsAndResolvers: 'always' // 强制每次参数变化时重建组件 } ];
方案二:缓存不同年份的窗口状态(保留用户操作)
如果需要记忆不同年份的窗口打开状态(切换回旧年份时,之前打开的窗口保持打开),可实现状态缓存逻辑。
实现步骤
- 修改
CalendarComponent,维护年份-窗口状态的映射:
import { Component } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { environment } from 'src/environments/environment'; @Component({ selector: 'app-calendar', templateUrl: './calendar.component.html', styleUrls: ['./calendar.component.scss'] }) export class CalendarComponent { title = environment.appName; showYear = 0; showDays = Array.from({length:25},(_,i)=>i+1); // 缓存结构:{ 年份: { 日期: 是否打开 } } windowStates: Record<number, Record<number, boolean>> = {}; constructor(private route: ActivatedRoute) { this.route.params.subscribe(params => { const year = +params['year']; this.showYear = year; this.title = `${environment.appName}: ${year}`; // 初始化当前年份的窗口状态(默认全部关闭) if (!this.windowStates[year]) { this.windowStates[year] = this.showDays.reduce((acc, day) => { acc[day] = false; return acc; }, {} as Record<number, boolean>); } }); } // 接收子组件的状态变化,更新缓存 updateWindowState(day: number, isOpen: boolean) { if (this.windowStates[this.showYear]) { this.windowStates[this.showYear][day] = isOpen; } } }
- 修改
CalendarComponent模板,传递缓存状态并绑定事件:
<div class="window-wrap"> <div class="window-place" *ngFor="let day of showDays"> <aoc-window [year]="showYear" [day]="day" [initialOpen]="windowStates[showYear][day]" (stateChanged)="updateWindowState(day, $event)"> </aoc-window> </div> </div>
- 修改
WindowComponent,支持外部控制状态并反馈变化:
import { Component, Input, Output, EventEmitter, OnChanges, SimpleChanges } from '@angular/core'; // ...其他导入 @Component({ selector: 'aoc-window', templateUrl: './window.component.html', styleUrls: ['./window.component.scss'] }) export class WindowComponent implements OnChanges { @Input() year: number = 0; @Input() day: number = 0; @Input() initialOpen: boolean = false; @Output() stateChanged = new EventEmitter<boolean>(); aocResponse?: AOCResponse | undefined; isOpen: boolean = false; constructor(private aocService: WindowService) { } ngOnChanges(changes: SimpleChanges) { // 当外部传入的初始状态变化时,同步本地状态 if (changes['initialOpen']) { this.isOpen = this.initialOpen; // 如果状态变为打开且未加载数据,自动请求 if (this.isOpen && !this.aocResponse) { this.getAOCResponse(); } } } open() { this.isOpen = true; this.stateChanged.emit(true); this.getAOCResponse(); } getAOCResponse() { const callPath = `${environment.aocPath}/${this.year}/${this.day}`; this.aocService.getAOCAnswer(callPath) .subscribe(aocResponse => { this.aocResponse = aocResponse; }, error => { console.error(error); this.aocResponse = { answer: 'Failed' } }); } }
内容的提问来源于stack exchange,提问作者Tim L
相关产品推荐
相关产品推荐

