如何在Angular应用加载前从ngx-cookie-service取值,避免登录页闪屏?
问题描述
刷新页面时,应用启动阶段从Cookie读取认证信息存在100-400ms的延迟,导致用户会短暂看到登录页,待Cookie值获取完成后又自动跳回首页。需要实现先完成Cookie加载,再决定跳转登录页还是首页,避免页面闪烁。
现有代码
app.component.html
<div id="app-main-container" style="height: 100vh; overflow: hidden;" *ngIf="globals.isAuthenticated; else login"> <app-side-nav></app-side-nav> <div class="main"> <app-nav-bar></app-nav-bar> <router-outlet></router-outlet> <app-footer></app-footer> </div> </div>
Globals服务代码
// globals get isAuthenticated(): boolean { return !!(this.auth) } get auth() { if (this._auth != null) { return this._auth; } else { const authJson = this.cookieService.get('auth'); if (!authJson) { console.warn("Auth cookie is missing"); } // Attempt to parse only if loggedUserJson is not null or undefined const data = authJson ? JSON.parse(authJson) : null; if (data) { this._auth = data; return this._auth; } else { this._auth = null; return this._auth; } } } constructor( private cookieService: CookieService ) {}
解决方案
核心思路是将同步读取Cookie的逻辑改为异步初始化,等待认证状态确定后再渲染页面或处理路由跳转,避免模板提前判断导致的闪烁。
方案一:组件内异步初始化认证状态
1. 修改Globals服务,添加异步初始化方法
// globals private _isAuthenticated = false; private _auth: any = null; private _initPromise: Promise<void> | null = null; // 改为直接返回存储的状态,不再实时读取Cookie get isAuthenticated(): boolean { return this._isAuthenticated; } get auth() { return this._auth; } constructor(private cookieService: CookieService) {} // 异步初始化认证状态 initAuth(): Promise<void> { if (this._initPromise) { return this._initPromise; } this._initPromise = new Promise((resolve) => { const authJson = this.cookieService.get('auth'); if (!authJson) { console.warn("Auth cookie is missing"); this._isAuthenticated = false; this._auth = null; resolve(); return; } try { const data = JSON.parse(authJson); this._auth = data ?? null; this._isAuthenticated = !!this._auth; } catch (e) { console.error("解析认证Cookie失败", e); this._auth = null; this._isAuthenticated = false; } resolve(); }); return this._initPromise; }
2. 修改AppComponent,等待初始化完成后渲染
// app.component.ts import { Component, OnInit } from '@angular/core'; import { Globals } from './path-to-your-globals.service'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit { authInitialized = false; constructor(private globals: Globals) {} ngOnInit(): void { this.globals.initAuth().then(() => { this.authInitialized = true; }); } }
3. 修改模板,先显示加载状态,再渲染对应内容
<!-- 加载状态:可替换为自定义加载动画 --> <div *ngIf="!authInitialized" style="display: flex; justify-content: center; align-items: center; height: 100vh;"> <div>加载中...</div> </div> <!-- 初始化完成后判断显示首页或登录页 --> <div id="app-main-container" style="height: 100vh; overflow: hidden;" *ngIf="authInitialized && globals.isAuthenticated; else login" > <app-side-nav></app-side-nav> <div class="main"> <app-nav-bar></app-nav-bar> <router-outlet></router-outlet> <app-footer></app-footer> </div> </div> <ng-template #login> <!-- 登录页组件 --> <app-login></app-login> </ng-template>
方案二:使用路由守卫控制页面访问
如果应用依赖路由导航,可通过路由守卫在页面加载前完成认证状态初始化,避免页面跳转闪烁。
1. 实现AuthGuard守卫
// auth.guard.ts import { Injectable } from '@angular/core'; import { CanActivate, Router } from '@angular/router'; import { Globals } from './path-to-your-globals.service'; @Injectable({ providedIn: 'root' }) export class AuthGuard implements CanActivate { constructor(private globals: Globals, private router: Router) {} async canActivate(): Promise<boolean> { // 等待认证状态初始化完成 await this.globals.initAuth(); if (this.globals.isAuthenticated) { return true; // 允许进入首页 } else { this.router.navigate(['/login']); // 跳转到登录页 return false; } } }
2. 在路由配置中添加守卫
// app-routing.module.ts import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { AuthGuard } from './auth.guard'; import { HomeComponent } from './home/home.component'; import { LoginComponent } from './login/login.component'; const routes: Routes = [ { path: '', component: HomeComponent, canActivate: [AuthGuard] }, { path: 'login', component: LoginComponent }, { path: '**', redirectTo: '' } ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule {}
3. 模板简化(可选)
此时AppComponent模板可直接渲染首页内容,路由守卫会自动处理跳转逻辑:
<div id="app-main-container" style="height: 100vh; overflow: hidden;"> <app-side-nav></app-side-nav> <div class="main"> <app-nav-bar></app-nav-bar> <router-outlet></router-outlet> <app-footer></app-footer> </div> </div>
内容的提问来源于stack exchange,提问作者e Res
相关产品推荐
相关产品推荐

