Angular 4跨组件修改变量:自定义加载倒计时时长问题
问题分析与解决方案
你遇到的核心问题是用错了组件通信方式:EventEmitter只适用于父子组件嵌套的场景(比如把<app-loading>直接写在home.component.html里作为子组件),但你是通过router.navigate跳转到独立的loading路由页面,这时候两个组件没有父子层级关系,EventEmitter根本无法传递数据。
下面给你两种最常用的解决方案,按优先级推荐:
方案一:通过路由参数传递倒计时时长(最直接)
这种方式不需要额外依赖,利用Angular路由的参数传递功能即可实现:
1. 修改home.component.ts的路由跳转逻辑
把倒计时时长作为路由参数传递:
import { Router } from '@angular/router'; // ...其他代码 applyChanges(){ this.dashboard.applyChanges() .catch(err => { console.log("There was an error: "+err.status); console.log("There was an error: "+err.statusText); return Observable.throw(err); }) .subscribe(data => { // 把时长作为路由参数传递 this.router.navigate(['/loading', { duration: 34 }]); }); }
2. 修改loading.component.ts获取路由参数
首先导入ActivatedRoute,然后在组件中获取参数并初始化倒计时:
import { Component, OnInit, OnDestroy } from '@angular/core'; import { AuthGuard } from '../guard/auth.guard'; import { Title } from '@angular/platform-browser'; import { ActivatedRoute } from '@angular/router'; // 新增导入 @Component({ selector: 'app-loading', templateUrl: './loading.component.html', styleUrls: ['./loading.component.css'] }) export class LoadingComponent implements OnInit, OnDestroy { // 新增OnDestroy public timeLeft; public intervalId; constructor( public titleService: Title, public guard: AuthGuard, private route: ActivatedRoute // 注入路由服务 ) { } ngOnInit() { this.titleService.setTitle("Loading... | something"); localStorage.removeItem('statusInfo'); // 订阅路由参数,获取传递的时长 this.route.paramMap.subscribe(params => { // 把参数转为数字,设置默认值10秒(可选) this.timeLeft = params.get('duration') ? +params.get('duration') : 10; this.startCounter(); // 拿到参数后再启动倒计时 }); } startCounter() { this.intervalId = setInterval(() => { if (this.timeLeft <= 1) { // 修正判断条件,防止负数 clearInterval(this.intervalId); // 修正拼写错误:你原来写的interValId是大小写错误 // 这里可以添加倒计时结束后的操作,比如跳转页面 // this.router.navigate(['/home']); } this.timeLeft--; }, 1000); } // 组件销毁时清理定时器,防止内存泄漏 ngOnDestroy() { if (this.intervalId) { clearInterval(this.intervalId); } } }
3. 清理无效代码
删除loading.component.html中的无效事件绑定:
<!-- 删掉这个事件绑定:(loadingScreenStarted)="onScreenStart($event)" --> <div class="container container-table"> <!-- 原有内容保持不变 --> </div>
方案二:通过共享服务传递数据(更灵活,适合复杂场景)
如果后续需要传递更多数据给loading组件,或者多个组件都要控制loading时长,推荐用共享服务:
1. 创建共享服务loading.service.ts
import { Injectable } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class LoadingService { // BehaviorSubject会保存最新值,新订阅者能直接拿到当前值 private durationSubject = new BehaviorSubject<number>(10); // 对外暴露可观察对象,防止外部直接修改Subject duration$ = this.durationSubject.asObservable(); // 设置倒计时时长的方法 setDuration(duration: number) { this.durationSubject.next(duration); } }
2. 修改home.component.ts调用服务
import { LoadingService } from '../services/loading.service'; // 导入服务 // ...其他代码 constructor( private dashboard: DashboardService, // 你的原有服务 private router: Router, private loadingService: LoadingService // 注入共享服务 ) { } applyChanges(){ this.dashboard.applyChanges() .catch(err => { console.log("There was an error: "+err.status); console.log("There was an error: "+err.statusText); return Observable.throw(err); }) .subscribe(data => { // 通过服务设置时长 this.loadingService.setDuration(34); this.router.navigate(['/loading']); }); }
3. 修改loading.component.ts订阅服务
import { Component, OnInit, OnDestroy } from '@angular/core'; import { AuthGuard } from '../guard/auth.guard'; import { Title } from '@angular/platform-browser'; import { LoadingService } from '../services/loading.service'; // 导入服务 import { Subscription } from 'rxjs'; // 导入订阅对象,用于清理 @Component({ selector: 'app-loading', templateUrl: './loading.component.html', styleUrls: ['./loading.component.css'] }) export class LoadingComponent implements OnInit, OnDestroy { public timeLeft; public intervalId; private durationSub: Subscription; // 保存订阅引用 constructor( public titleService: Title, public guard: AuthGuard, private loadingService: LoadingService // 注入服务 ) { } ngOnInit() { this.titleService.setTitle("Loading... | something"); localStorage.removeItem('statusInfo'); // 订阅服务中的时长数据 this.durationSub = this.loadingService.duration$.subscribe(duration => { this.timeLeft = duration; this.startCounter(); }); } startCounter() { this.intervalId = setInterval(() => { if (this.timeLeft <= 1) { clearInterval(this.intervalId); // 倒计时结束后的操作 } this.timeLeft--; }, 1000); } ngOnDestroy() { // 清理定时器和订阅,防止内存泄漏 if (this.intervalId) clearInterval(this.intervalId); if (this.durationSub) this.durationSub.unsubscribe(); } }
额外注意点
- 你原来的
startCounter里有拼写错误:clearInterval(this.interValId);应该是clearInterval(this.intervalId);(驼峰大小写要一致) - 建议在组件销毁时清理定时器和订阅,避免内存泄漏
- 如果用路由参数,记得在路由配置中允许可选参数(Angular默认支持,不需要额外配置)
内容的提问来源于stack exchange,提问作者user7339086
相关产品推荐
相关产品推荐

