Angular组件重载后如何让计时器持续运行而非重启
Angular页面重载后保持计时器持续运行
问题分析
你当前的核心问题是:组件重载时ngOnInit会重新执行startTimer(86400),导致计时器每次都从86400秒重置启动。要实现页面重载后计时器继续运行,关键是保存计时器的剩余状态,并在组件初始化时恢复该状态。
解决方案一:利用LocalStorage存储剩余时间
LocalStorage可在页面刷新后保留数据,适合存储计时器的剩余秒数,实现状态持久化:
修改组件代码
- 改造
startTimer函数,优先从LocalStorage读取剩余时间,每次更新时同步存储:
startTimer(secsToStart: number): void { // 优先读取本地存储的剩余时间,无数据则用传入的初始值 let start: number = Number(localStorage.getItem('remainingSeconds')) || secsToStart; var h: number; var m: number; var s: number; var temp: number; var timer: any = setInterval(() => { h = Math.floor(start / 60 / 60); temp = start - h * 60 * 60; m = Math.floor(temp / 60); temp = temp - m * 60; s = temp; var hour = h < 10 ? '0' + h : h; var minute = m < 10 ? '0' + m : m; var second = s < 10 ? '0' + s : s; this.expirationCounter = hour + ':' + minute + ':' + second; if (start <= 0) { clearInterval(timer); this.expirationCounter = 'Expired'; this.timeIsUp = true; this.tasks = []; // 计时器结束,清除本地存储数据 localStorage.removeItem('remainingSeconds'); } else if (this.donePushed) { clearInterval(timer); console.log(start); // 任务完成,清除本地存储数据 localStorage.removeItem('remainingSeconds'); } start--; // 每次更新剩余时间后同步到本地存储 localStorage.setItem('remainingSeconds', start.toString()); }, 1000); }
ngOnInit无需修改,startTimer会自动读取本地存储的状态:
ngOnInit() { this.tasks = this.tasksService.getTasks(); this.startTimer(86400); this.excuseForm = this.fb.group({ excuse: '', }); this.excuseForm.valueChanges.subscribe(console.log); }
解决方案二:使用Angular单例服务管理计时器状态
Angular服务默认是单例模式,组件销毁重建时服务的状态不会丢失,适合跨组件或组件重载时保留计时器状态:
1. 创建TimerService
import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class TimerService { remainingSeconds: number = 86400; expirationCounter: string = ''; timeIsUp = false; donePushed = false; timer: any; startTimer(): void { if (this.timer) clearInterval(this.timer); this.timer = setInterval(() => { const h = Math.floor(this.remainingSeconds / 60 / 60); const temp = this.remainingSeconds - h * 60 * 60; const m = Math.floor(temp / 60); const s = temp - m * 60; const hour = h < 10 ? '0' + h : h; const minute = m < 10 ? '0' + m : m; const second = s < 10 ? '0' + s : s; this.expirationCounter = `${hour}:${minute}:${second}`; if (this.remainingSeconds <= 0) { clearInterval(this.timer); this.expirationCounter = 'Expired'; this.timeIsUp = true; } else if (this.donePushed) { clearInterval(this.timer); } this.remainingSeconds--; }, 1000); } stopTimer(): void { if (this.timer) { clearInterval(this.timer); } } }
2. 修改组件代码
import { OnInit, OnDestroy } from '@angular/core'; // 导入新增的TimerService import { TimerService } from '../services/timer.service'; @Component({ selector: 'app-task-countdown', templateUrl: './task-countdown.component.html', styleUrls: ['./task-countdown.component.css'], }) export class TaskCountdownComponent implements OnInit, OnDestroy { @Input() tasks!: Tasks[]; excuse!: Loosers[]; excuseForm!: FormGroup; constructor( private fb: FormBuilder, private tasksService: TasksService, private excuseService: ExcuseService, private router: Router, public timerService: TimerService // 注入TimerService ) {} ngOnInit() { this.tasks = this.tasksService.getTasks(); // 若计时器未启动,则启动服务中的计时器 if (!this.timerService.timer) { this.timerService.startTimer(); } this.excuseForm = this.fb.group({ excuse: '', }); this.excuseForm.valueChanges.subscribe(console.log); } ngOnDestroy() { // 组件销毁时无需停止计时器,服务会保留状态;若需页面关闭时停止,可调用this.timerService.stopTimer() } addExcuse() { const excuseValue = this.excuseForm.value; this.excuseService.addExcuse(excuseValue); this.router.navigate(['/loosers']); } onTaskDone() { this.timerService.donePushed = true; } }
3. 修改HTML模板
直接绑定服务中的状态属性:
<app-nav-bar></app-nav-bar> <div *ngFor="let tasks of tasks"> <p>{{ tasks.task }}</p> <button (click)="onTaskDone()">Done</button> </div> <div> <span id="myTimeCounter">{{ timerService.expirationCounter }}</span> </div> <div *ngIf="timerService.timeIsUp"> <form [formGroup]="excuseForm"> <input type="text" placeholder="write down your excuses .. " formControlName="excuse" /> <button (click)="addExcuse()">Add</button> </form> </div>
方案对比
- 方案一适合单组件场景,数据存在浏览器本地,清除浏览器缓存会丢失数据;
- 方案二更适合多组件共享计时器状态,服务状态在页面刷新时会重置,若需持久化可结合LocalStorage在服务中读写数据。
内容的提问来源于stack exchange,提问作者Ilze
相关产品推荐
相关产品推荐

