如何获取Angular Route Start与Route End事件并实现路由加载进度条?
嘿,这个需求我帮很多开发者解决过,Angular的路由事件系统刚好能完美搞定进度条的需求,我一步步给你拆解实现方式:
一、核心思路:监听路由生命周期事件
Angular的Router模块会在路由跳转的整个过程中发出一系列事件,我们需要重点关注这几个:
NavigationStart:路由跳转开始时触发,这是启动进度条的信号NavigationEnd:路由跳转成功完成时触发NavigationCancel:路由跳转被取消时触发(比如用户快速切换路由)NavigationError:路由跳转失败时触发
这四个事件能覆盖路由跳转的完整周期,包括数据加载(比如路由守卫里的resolve异步操作)的过程。
二、具体实现步骤
1. 准备进度条组件(自定义或用现成库)
如果不想用第三方库,自己写一个极简的进度条组件很简单:
import { Component, Input } from '@angular/core'; @Component({ selector: 'app-progress-bar', template: `<div class="progress-bar" [style.width.%]="progress"></div>`, styles: [` .progress-bar { position: fixed; top: 0; left: 0; height: 3px; background: #1976d2; /* Angular主题色 */ transition: width 0.2s ease-in-out; z-index: 9999; /* 确保在最上层 */ } `] }) export class ProgressBarComponent { @Input() progress = 0; // 接收外部传入的进度值 }
当然你也可以用ngx-progressbar这类成熟库,自定义程度更高,但上面的代码足够满足基础需求。
2. 在根组件中监听路由事件
把进度条放在根组件(比如AppComponent)里,这样就能全局监听路由变化:
import { Component } from '@angular/core'; import { Router, NavigationStart, NavigationEnd, NavigationCancel, NavigationError } from '@angular/router'; @Component({ selector: 'app-root', template: ` <app-progress-bar [progress]="currentProgress"></app-progress-bar> <router-outlet></router-outlet> ` }) export class AppComponent { currentProgress = 0; private progressInterval: any; // 用于存储定时器,方便清理 constructor(private router: Router) { this.subscribeToRouterEvents(); } private subscribeToRouterEvents(): void { this.router.events.subscribe(event => { if (event instanceof NavigationStart) { // 路由开始:初始化进度条并启动递增动画 this.currentProgress = 20; this.startProgressIncrement(); } // 路由结束的三种情况:成功、取消、失败 if ([NavigationEnd, NavigationCancel, NavigationError].some(evt => event instanceof evt)) { // 完成进度条,然后重置 this.currentProgress = 100; clearInterval(this.progressInterval); // 延迟重置,避免进度条闪一下就消失 setTimeout(() => { this.currentProgress = 0; }, 300); } }); } private startProgressIncrement(): void { // 清理之前的定时器,避免多个路由跳转时冲突 clearInterval(this.progressInterval); // 每隔200ms递增进度,模拟加载过程 this.progressInterval = setInterval(() => { if (this.currentProgress < 80) { this.currentProgress += 10; } }, 200); } }
3. 处理异步数据加载的特殊情况
如果你的路由使用了resolve守卫(在路由激活前加载数据),或者组件内有ngOnInit里的异步请求,NavigationEnd会在数据加载完成后才触发,所以上面的代码已经能覆盖这种情况。
但如果是组件内的异步加载(比如进入页面后才发起请求),你需要额外在组件里通过服务传递加载状态,让根组件知道什么时候真正完成加载,再结束进度条。比如:
- 创建一个
LoadingService,提供setLoading和getLoading方法 - 组件发起请求时调用
setLoading(true),请求完成后调用setLoading(false) - 根组件订阅
LoadingService的状态,动态调整进度条
三、小技巧优化体验
- 给进度条加个过渡动画,让增长更平滑(上面的CSS已经加了
transition) - 避免进度条直接跳到100%,可以在路由结束时先拉到90%,延迟100ms再到100%,更符合用户感知
- 清理定时器很重要,不然快速切换路由会导致多个定时器同时运行,进度条混乱
内容的提问来源于stack exchange,提问作者Daniel Däschle
相关产品推荐
相关产品推荐

