Angular自定义预加载策略
这篇文章由 DeathGhost 编辑,发布于
归类于 Angular » 👋分享到微博 当前评论 0 条。
预加载是介于直接加载与懒加载的一种方式。懒加载是为了降低初始化所需时间,预加载是为了提升即将进入路由模块时间。
Angular实际应用中我们会根据业务或角色权限拆分出各个模块,然后在路由中除初始化模块外设置懒加载。但是为了能够快速导航到即将进入的模块,我们会对路由模块设置预加载。Angular路由提供了preloadingStrategy
配置属性,这个属性定义了用于预加载和处理延迟加载的Angular模块的逻辑,将PreloadAllModules
指定给preloadingStrategy
。
import { RouterModule, PreloadAllModules } from '@angular/router';
// …
RouterModule.forRoot([
…
], {
preloadingStrategy: PreloadAllModules
})
// …
详情可阅读上篇文章关于“Angular路由预加载”。
今天谈谈另一种需求场景,就是对各个模块可配置性预加载;上述方法默认是预加载所有模块,但随着业务模块增多,未必是个好方法,对服务器资源也是一种消耗。我们设置一个自定义预加载策略,然后对每个模块进行选择性配置是否对其预加载。
创建preloading-strategy.service.ts预加载策略服务
import { Injectable } from '@angular/core';
import { PreloadingStrategy, Route } from '@angular/router';
import { Observable, of } from 'rxjs';
@Injectable({
providedIn: 'root',
})
export class SelectivePreloadingStrategyService implements PreloadingStrategy {
preloadedModules: string[] = [];
preload(route: Route, load: () => Observable<any>): Observable<any> {
if (route.data && route.data['preload']) {
this.preloadedModules.push(route.path);
return load();
} else {
return of(null);
}
}
}
在路由模块中导入并配置
import { PreloadingStrategyService } from '../preloading-strategy.service';
// ...
{ path: '', loadChildren: () => import('./user/user.module').then(m => m.UserModule), data: {preload: false} },
// ...
{ preloadingStrategy: PreloadingStrategyService, relativeLinkResolution: 'legacy' }
// ...
其中data: {preload: true}
就是设置是否预加载。
那么,问题来了,未设置预加载的模块,还是原来的懒加载。我们都知道,懒加载情况下,点击跳转路由时,若该模块未加载完成,当前触发犹如未操作一般,用户体验非常糟糕。这时,我们可以在路由插座上设置CSS过渡效果以缓解这个尴尬的场面。
路由插座RouterOutlet中模块加载设置CSS过渡样式
RouterOutlet是一个占位符,Angular 会根据当前的路由器状态动态填充它。我们在页面整体布局结构中会使用到它。
<router-outlet>
<div class="pageLoad" *ngIf="loadModule">
<div class="loading_module">
<div class="dot white"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
</div>
<p class="text">数据模块加载中,请耐心等待...</p>
</div>
</router-outlet>
import { Router, NavigationEnd, RouterEvent, NavigationStart, GuardsCheckEnd } from '@angular/router';
// ...
loadModule: boolean;
constructor(
private router: Router,
) {
this.loadModule = true;
this.router.events.subscribe(
(event: RouterEvent): void => {
if (event instanceof NavigationStart) {
this.loadModule = true;
} else if (event instanceof NavigationEnd) {
this.loadModule = false;
} else if (event instanceof GuardsCheckEnd) {
this.loadModule = false;
} else if () {}
}
);
}
// ...
NavigationStart
导航开始时,显示定义的那段“pageLoad”,当NavigationEnd
导航成功结束时将插座中的那段HTML
文本移除掉。
过渡样式,示例中用SCSS文件编写。
.pageLoad{
position: absolute;
left:0;
right:0;
top:0;
bottom:0;
background:white;
display:flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 1986;
.text{
margin-top: 10em;
letter-spacing: 1px;
color:#999;
font-size: 12px;
text-align: center;
}
}
.loading_module {
position: absolute;
margin: auto;
top: 0; bottom: 0; left: 0; right: 0;
width: 6.250em; height: 6.250em;
animation: rotate 2.4s linear infinite;
.white {
top: 0; bottom: 0; left: 0; right: 0;
background: white;
animation: flash 2.4s linear infinite;
opacity: 0;
}
.dot {
position: absolute;
margin: auto;
width: 2.4em; height: 2.4em;
border-radius: 100%;
transition: all 1s ease;
}
.dot:nth-child(2) { top: 0; bottom: 0; left: 0; background: #FF4444; animation: dotsY 2.4s linear infinite; }
.dot:nth-child(3) { left: 0; right: 0; top: 0; background: #FFBB33; animation: dotsX 2.4s linear infinite; }
.dot:nth-child(4) { top: 0; bottom: 0; right: 0; background: #99CC00; animation: dotsY 2.4s linear infinite; }
.dot:nth-child(5) { left: 0; right: 0; bottom: 0; background: #33B5E5; animation: dotsX 2.4s linear infinite; }
}
@keyframes rotate {
0% { transform: rotate( 0 ); }
10% { width: 6.250em; height: 6.250em; }
66% { width: 2.4em; height: 2.4em; }
100%{ transform: rotate(360deg); width: 6.250em; height: 6.250em; }
}
@keyframes dotsY {
66% { opacity: .1; width: 2.4em; }
77%{ opacity: 1; width: 0; }
}
@keyframes dotsX {
66% { opacity: .1; height: 2.4em;}
77%{ opacity: 1; height: 0; }
}
@keyframes flash {
33% { opacity: 0; border-radius: 0%; }
55%{ opacity: .6; border-radius: 100%; }
66%{ opacity: 0; }
}
选择性预加载,可以针对存在不同管理角色,加载相对应的所涉及的模块。避免加载一些非本角色的模块,消耗占用服务端及其用户资源。