如何在AngularJS中实现多HTTP请求进度条与页面加载进度显示
我太懂你这种烦恼了!第三方加载进度条插件时不时掉链子,尤其是连续发起好几个请求的时候,进度条直接“失踪”,完全不靠谱。既然你已经了解HTTP拦截器的基本原理,那咱们自己动手实现一个稳定可控的方案,再也不用看插件脸色!
实现基于HTTP Interceptor的加载进度条
1. 核心思路:用拦截器精准追踪请求生命周期
HTTP拦截器可以捕获所有请求的发起、响应完成(包括失败)事件,我们可以用一个服务来维护当前活跃的请求数量,再根据这个数量计算进度,或者控制进度条的显示与更新——完全自己掌控,再也不会出现进度条跳票的情况!
2. 第一步:创建进度管理服务
先搞一个专门的服务,负责追踪请求数量、计算进度值,并且通过RxJS的Subject把进度状态发送给UI组件:
import { Injectable } from '@angular/core'; import { BehaviorSubject, Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class LoadingProgressService { private activeRequests = 0; private progressSubject = new BehaviorSubject<number>(0); public progress$: Observable<number> = this.progressSubject.asObservable(); // 发起新请求时调用 startRequest(): void { this.activeRequests++; // 初始进度设为20%,避免一直卡在0的尴尬 this.updateProgress(20); } // 请求结束(成功/失败都算)时调用 endRequest(): void { this.activeRequests--; if (this.activeRequests <= 0) { this.activeRequests = 0; // 最后直接拉满到100%,给用户明确的完成反馈 this.updateProgress(100); // 延迟重置进度,让用户能看到完成的动画 setTimeout(() => { this.progressSubject.next(0); }, 300); } else { // 根据剩余活跃请求数计算进度,这里做了简单的线性分配 const progress = 20 + (80 * (1 - this.activeRequests / 10)); // 假设最多同时10个请求,可按需调整 this.updateProgress(Math.min(Math.round(progress), 90)); // 最多到90%,留到最后一步拉满 } } private updateProgress(value: number): void { this.progressSubject.next(value); } // 可选:手动重置进度(比如路由切换时) reset(): void { this.activeRequests = 0; this.progressSubject.next(0); } }
3. 第二步:实现HTTP拦截器
在拦截器里调用上面的服务,拦截所有请求的开始和结束:
import { Injectable } from '@angular/core'; import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http'; import { Observable } from 'rxjs'; import { finalize } from 'rxjs/operators'; import { LoadingProgressService } from './loading-progress.service'; @Injectable() export class LoadingProgressInterceptor implements HttpInterceptor { constructor(private loadingProgressService: LoadingProgressService) {} intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> { // 可以跳过不需要显示进度的请求,比如静态资源、OPTIONS预检请求 if (request.url.includes('assets/') || request.method === 'OPTIONS') { return next.handle(request); } // 请求发起时通知服务 this.loadingProgressService.startRequest(); // 用finalize确保无论请求成功失败,都通知服务结束 return next.handle(request).pipe( finalize(() => { this.loadingProgressService.endRequest(); }) ); } }
别忘了在app.module.ts里注册这个拦截器:
import { HTTP_INTERCEPTORS } from '@angular/common/http'; import { LoadingProgressInterceptor } from './loading-progress.interceptor'; @NgModule({ providers: [ { provide: HTTP_INTERCEPTORS, useClass: LoadingProgressInterceptor, multi: true } ] }) export class AppModule { }
4. 第三步:创建进度条UI组件
现在把进度状态渲染成直观的顶部进度条:
<div class="loading-progress" *ngIf="(progress$ | async) > 0"> <div class="loading-progress-bar" [style.width.%]="progress$ | async"></div> </div>
对应的CSS:
.loading-progress { position: fixed; top: 0; left: 0; right: 0; height: 3px; background-color: #f0f0f0; z-index: 9999; } .loading-progress-bar { height: 100%; background-color: #1976d2; /* Angular主题色,可按需修改 */ transition: width 0.2s ease-in-out; }
组件逻辑:
import { Component } from '@angular/core'; import { LoadingProgressService } from './loading-progress.service'; import { Observable } from 'rxjs'; @Component({ selector: 'app-loading-progress', templateUrl: './loading-progress.component.html', styleUrls: ['./loading-progress.component.css'] }) export class LoadingProgressComponent { progress$: Observable<number>; constructor(private loadingProgressService: LoadingProgressService) { this.progress$ = this.loadingProgressService.progress$; } }
最后把这个组件加到app.component.html的最顶部,就能全局生效啦!
5. 可选优化点
- 页面级进度:配合路由守卫,进入新页面时调用
reset()重置进度,实现单个页面的请求进度追踪。 - 精准进度计算:如果能提前知道当前页面的请求总数,可以在服务里记录初始总请求数,进度计算会更平滑。
- 动画增强:给进度条添加完成时的淡出动画,或者不同状态的颜色变化(比如加载中蓝色,完成时绿色)。
这个方案完全自定义,每一个请求的生命周期都被精准控制——不管是5个还是10个请求,进度条都会按预期更新,再也不会出现“失踪”的情况!
内容的提问来源于stack exchange,提问作者vikrant chauhan
相关产品推荐
相关产品推荐

