loading.service.tsimport { Injectable } from '@angular/core';
import { RouteConfigLoadEnd, RouteConfigLoadStart, Router } from '@angular/router';
import { Observable } from 'rxjs';
import { filter, map } from 'rxjs/operators';
@Injectable({ providedIn: 'root' })
export class LoadingService {
public readonly loading$: Observable<boolean>;
constructor(router: Router) {
this.loading$ = router.events.pipe(
filter((event) => event instanceof RouteConfigLoadStart || event instanceof RouteConfigLoadEnd),
map((event) => event instanceof RouteConfigLoadStart)
);
}
}
app.component.css.loadbar.active {
height: 2px;
animation: loadbar-progress 3s forwards cubic-bezier(0, 1, 1, 1);
}
.loadbar.finish {
animation: loadbar-finish 0.3s;
}
@keyframes loadbar-progress {
from { width: 0; }
to { width: 90%; }
}
@keyframes loadbar-finish {
from { width: 90%; }
to { width: 100%; }
}
app.component.tsexport class AppComponent {
public readonly loading$?: Observable<boolean>;
public readonly finish$?: Observable<boolean>;
constructor(@Inject(PLATFORM_ID) platform: object, { loading$ }: LoadingService) {
if (isPlatformBrowser(platform)) {
this.loading$ = loading$.pipe(delayWhen((v) => interval(v ? 0 : 450)));
this.finish$ = loading$.pipe(map((v) => !v));
}
}
}
app.component.html<div
class="absolute bg-blue-500 loadbar z-50 w-full top-0 opacity-50"
[ngClass]="{ finish: finish$ | async, active: loading$ | async }"
></div>