You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:11:56