Angular如何在resolve服务获取userInfo完成后再隐藏splash screen?
问题原因
- 启动屏的显示逻辑存在时机错位:放在
<app-root>标签内部的静态内容,仅会在Angular根组件未完成初始化渲染时显示,一旦Angular完成根组件初始化,就会清空<app-root>内所有原有静态内容,替换为根组件的模板内容。 - 路由resolve守卫的执行时机晚于根组件初始化:resolve是路由层面对应路由组件加载前的前置逻辑,会在根组件初始化完成后、对应路由组件渲染前执行,所以会出现resolve还在等待接口返回,启动屏已经被清空的白屏问题。
- 你的resolve预加载逻辑本身没有问题,问题出在启动屏的控制逻辑没有和resolve的完成时机绑定。
解决方案
方案1:将启动屏移入根组件模板,与路由加载状态绑定
这种方案无需修改现有resolve逻辑,调整启动屏的控制方式即可:
- 将原本放在
index.html中<app-root>内部的静态启动屏代码,移到根组件(一般为AppComponent)的模板中,通过状态变量控制显隐:
<!-- AppComponent 模板文件 --> <div class="splash-screen" *ngIf="showSplash"> </div> <router-outlet></router-outlet>
- 在根组件中监听路由导航完成事件(此时resolve已经执行完毕),控制启动屏隐藏:
// AppComponent 逻辑文件 import { Component } from '@angular/core'; import { NavigationEnd, Router } from '@angular/router'; import { filter } from 'rxjs'; @Component({ selector: 'app-root', templateUrl: './app.component.html' }) export class AppComponent { showSplash = true; constructor(private router: Router) { this.router.events.pipe( filter(event => event instanceof NavigationEnd) ).subscribe(() => { // 可根据需求增加短延迟保证主组件渲染完成,不需要可直接赋值为false setTimeout(() => this.showSplash = false, 80); }); } }
- 删除
index.html中<app-root>内部原来的静态启动屏代码即可。
方案2:使用APP_INITIALIZER将数据预加载提前到应用初始化阶段
如果userInfo是全局通用数据,也可以将预加载逻辑提前到Angular应用初始化阶段,应用初始化完成前启动屏会一直显示:
- 在根模块
AppModule的providers中配置初始化加载器:
// AppModule 文件 import { NgModule, APP_INITIALIZER } from '@angular/core'; import { UserInfoService } from './services/user-info.service'; // 预加载用户信息的工厂函数 function loadUserInfoFactory(userService: UserInfoService) { return () => userService.getCurrentUserInfo().toPromise(); } @NgModule({ // ...其他配置 providers: [ { provide: APP_INITIALIZER, useFactory: loadUserInfoFactory, deps: [UserInfoService], multi: true } ] }) export class AppModule { }
- 这种方式无需再配置路由的resolve,根组件初始化完成后可以直接从
UserInfoService中读取已经加载好的用户信息,原本放在<app-root>内部的启动屏可以正常显示到数据加载完成,不会出现白屏。
内容的提问来源于stack exchange,提问作者adopilot
相关产品推荐
相关产品推荐

