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

新标签页通过Resolver预取数据时添加进度条的实现方法

解决Angular Resolver加载时显示进度条的问题

你的问题很典型——Resolver在路由激活前获取数据,导致目标组件未渲染时出现空白,而依赖UI的进度条无法触发。这里有两个靠谱的解决方案,帮你在数据解析期间显示进度条:

方案1:利用路由事件全局监听导航状态

这个方案通过监听Angular的路由导航事件,在导航开始时显示进度条,完成/取消/出错时隐藏。优点是无需修改现有Resolver,覆盖所有路由场景:

  1. 在根组件(比如AppComponent)中订阅路由事件:
import { Component } from '@angular/core';
import { Router, NavigationStart, NavigationEnd, NavigationCancel, NavigationError } from '@angular/router';

@Component({
  selector: 'app-root',
  template: `
    <!-- 进度条放在router-outlet外部,确保始终能渲染 -->
    <div *ngIf="isLoading" class="fixed-top-progress-bar">
      <mat-progress-bar mode="indeterminate"></mat-progress-bar>
    </div>
    <router-outlet></router-outlet>
  `
})
export class AppComponent {
  isLoading = false;

  constructor(private router: Router) {
    this.router.events.subscribe(event => {
      if (event instanceof NavigationStart) {
        // 导航开始,立即显示进度条
        this.isLoading = true;
      } else if (event instanceof NavigationEnd || event instanceof NavigationCancel || event instanceof NavigationError) {
        // 导航结束(无论成功/失败/取消),隐藏进度条
        this.isLoading = false;
      }
    });
  }
}
  1. 给进度条加固定定位的CSS(比如fixed-top-progress-bar),确保它悬浮在页面顶部,不会被内容遮挡。

方案2:通过全局服务精准控制Resolver的加载状态

这个方案更精准,只在Resolver开始/结束数据获取时控制进度条,不会影响其他路由导航:

步骤1:创建全局Loading服务

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';

@Injectable({ providedIn: 'root' })
export class LoadingService {
  private isLoadingSubject = new BehaviorSubject<boolean>(false);
  // 对外暴露可观察对象,避免外部直接修改状态
  isLoading$ = this.isLoadingSubject.asObservable();

  show(): void {
    this.isLoadingSubject.next(true);
  }

  hide(): void {
    this.isLoadingSubject.next(false);
  }
}

步骤2:修改Resolver,添加进度条控制

用finalize操作符确保无论请求成功还是失败,进度条都会隐藏:

import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { DeviceService } from './device.service';
import { LoadingService } from './loading.service';
import { finalize } from 'rxjs/operators';

@Injectable({ providedIn: 'root' })
export class DeviceResolverService implements Resolve<any> {
  constructor(
    private deviceService: DeviceService,
    private loadingService: LoadingService
  ) {}

  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
    // 开始获取数据时显示进度条
    this.loadingService.show();
    
    return this.deviceService.getDeviceDetails(route.paramMap.get('id')).pipe(
      // 请求完成(成功/失败)后隐藏进度条
      finalize(() => this.loadingService.hide())
    );
  }
}

步骤3:在根组件中使用LoadingService控制进度条

import { Component } from '@angular/core';
import { LoadingService } from './loading.service';

@Component({
  selector: 'app-root',
  template: `
    <div *ngIf="isLoading$ | async" class="fixed-top-progress-bar">
      <mat-progress-bar mode="indeterminate"></mat-progress-bar>
    </div>
    <router-outlet></router-outlet>
  `
})
export class AppComponent {
  isLoading$ = this.loadingService.isLoading$;

  constructor(private loadingService: LoadingService) {}
}

注意事项

  • 进度条组件必须放在根组件的router-outlet外部,这样在路由未激活时也能渲染。
  • 如果使用Angular Material的进度条,记得导入MatProgressBarModule到你的模块中。
  • 方案2的优势是只针对Resolver的加载场景,不会在普通路由切换时(无Resolver)显示不必要的进度条。

内容的提问来源于stack exchange,提问作者user2900572

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 08:12:57