使用Router Outlet时,如何在组件切换间添加加载动画?
在Angular路由导航时添加加载动画(Router Outlet场景)
针对你提到的注册页面切换组件需8秒、使用Router Outlet导航的场景,以下是两种实用实现方案:
方案一:监听路由导航事件,全局显示加载动画
这种方式适用于路由切换过程(包括懒加载chunk下载、组件初始化)的等待状态,在根组件中统一控制加载界面的显示。
步骤1:在根组件中订阅路由事件
在app.component.ts中注入Router,监听导航开始/结束/失败/取消事件,维护加载状态:
import { Component } from '@angular/core'; import { Router, NavigationStart, NavigationEnd, NavigationError, NavigationCancel } from '@angular/router'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { isLoading = false; constructor(private router: Router) { this.router.events.subscribe(event => { // 导航开始时显示加载动画 if (event instanceof NavigationStart) { this.isLoading = true; } // 导航结束、失败或取消时隐藏加载动画 if (event instanceof NavigationEnd || event instanceof NavigationError || event instanceof NavigationCancel) { this.isLoading = false; } }); } }
步骤2:在根组件模板中添加加载动画
在Router Outlet旁插入加载元素,用*ngIf根据状态控制显示:
<!-- 全局加载覆盖层 --> <div *ngIf="isLoading" class="loading-overlay"> <div class="spinner"></div> </div> <!-- 路由出口 --> <router-outlet></router-outlet>
步骤3:添加加载动画样式
在app.component.css中定义加载动画的样式:
.loading-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(255,255,255,0.8); display: flex; justify-content: center; align-items: center; z-index: 9999; } .spinner { width: 50px; height: 50px; border: 5px solid #f3f3f3; border-top: 5px solid #3498db; border-radius: 50%; animation: spin 1s linear infinite; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
方案二:使用路由Resolve守卫,组件内显示加载状态
如果延迟是因为目标组件需要加载大量数据(而非路由本身),可以用Resolve守卫在路由激活前预加载数据,同时在组件内显示加载动画。
步骤1:创建Resolve数据加载服务
import { Injectable } from '@angular/core'; import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; import { Observable, of } from 'rxjs'; import { delay } from 'rxjs/operators'; @Injectable({ providedIn: 'root' }) export class DataResolveService implements Resolve<any> { resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> { // 模拟8秒的数据加载过程 return of({ content: '目标组件所需数据' }).pipe(delay(8000)); } }
步骤2:配置路由关联Resolve
在路由配置中指定该Resolve,确保数据加载完成后才激活组件:
import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import { TargetComponent } from './target/target.component'; import { DataResolveService } from './data-resolve.service'; const routes: Routes = [ { path: 'target', component: TargetComponent, resolve: { targetData: DataResolveService } } ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { }
步骤3:目标组件内控制加载状态
在目标组件中获取路由解析的数据,控制加载动画的显示:
import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; @Component({ selector: 'app-target', templateUrl: './target.component.html', styleUrls: ['./target.component.css'] }) export class TargetComponent implements OnInit { isLoading = true; componentData: any; constructor(private route: ActivatedRoute) { } ngOnInit(): void { // 获取路由解析完成的数据 this.componentData = this.route.snapshot.data['targetData']; this.isLoading = false; } }
目标组件模板:
<div *ngIf="isLoading" class="component-loading"> <div class="spinner"></div> <p>数据加载中...</p> </div> <div *ngIf="!isLoading" class="component-content"> <h2>组件内容</h2> <p>{{ componentData.content }}</p> </div>
补充说明
- 如果是懒加载模块导致的延迟,方案一的路由事件监听会自动覆盖,因为懒加载chunk下载时
NavigationStart触发,直到chunk加载完成才会触发NavigationEnd。 - 可以根据需求自定义加载动画的样式,比如更换spinner图标、添加文字提示等。
内容的提问来源于stack exchange,提问作者Zephyr
相关产品推荐
相关产品推荐

