在Angular 2中更改路线时如何显示加载屏幕?
当前的AngularRouter提供导航事件。您可以订阅这些内容并相应地更改UI。请记住要计入其他事件,例如,NavigationCancel并NavigationError在路由器转换失败时停止旋转器。
NavigationCancel
NavigationError
app.component.ts- 您的根组件
... import { Router, // import as RouterEvent to avoid confusion with the DOM Event Event as RouterEvent, NavigationStart, NavigationEnd, NavigationCancel, NavigationError } from '@angular/router' @Component({}) export class AppComponent { // Sets initial value to true to show loading spinner on first load loading = true constructor(private router: Router) { this.router.events.subscribe((e : RouterEvent) => { this.navigationInterceptor(e); }) } // Shows and hides the loading spinner during RouterEvent changes navigationInterceptor(event: RouterEvent): void { if (event instanceof NavigationStart) { this.loading = true } if (event instanceof NavigationEnd) { this.loading = false } // Set loading state to false in both of the below events to hide the spinner in case a request fails if (event instanceof NavigationCancel) { this.loading = false } if (event instanceof NavigationError) { this.loading = false } } }
app.component.html- 您的根视图
<div class="loading-overlay" *ngIf="loading"> <!-- show something fancy here, here with Angular 2 Material's loading bar or circle --> <md-progress-bar mode="indeterminate"></md-progress-bar> </div>
提高性能的答案 :如果您关心性能,有更好的方法,则实现起来会有些繁琐,但是提高性能值得进行额外的工作。代替使用*ngIf有条件地显示微调器,我们可以利用Angular的功能NgZone并Renderer打开/关闭微调器,这将在我们更改微调器的状态时绕过Angular的更改检测。与使用*ngIf或async管道相比,我发现这可以使动画更流畅。
*ngIf
NgZone
Renderer
async
这与我以前的回答类似,但有一些调整:
... import { Router, // import as RouterEvent to avoid confusion with the DOM Event Event as RouterEvent, NavigationStart, NavigationEnd, NavigationCancel, NavigationError } from '@angular/router' import {NgZone, Renderer, ElementRef, ViewChild} from '@angular/core' @Component({}) export class AppComponent { // Instead of holding a boolean value for whether the spinner // should show or not, we store a reference to the spinner element, // see template snippet below this script @ViewChild('spinnerElement') spinnerElement: ElementRef constructor(private router: Router, private ngZone: NgZone, private renderer: Renderer) { router.events.subscribe(this._navigationInterceptor) } // Shows and hides the loading spinner during RouterEvent changes private _navigationInterceptor(event: RouterEvent): void { if (event instanceof NavigationStart) { // We wanna run this function outside of Angular's zone to // bypass change detection this.ngZone.runOutsideAngular(() => { // For simplicity we are going to turn opacity on / off // you could add/remove a class for more advanced styling // and enter/leave animation of the spinner this.renderer.setElementStyle( this.spinnerElement.nativeElement, 'opacity', '1' ) }) } if (event instanceof NavigationEnd) { this._hideSpinner() } // Set loading state to false in both of the below events to // hide the spinner in case a request fails if (event instanceof NavigationCancel) { this._hideSpinner() } if (event instanceof NavigationError) { this._hideSpinner() } } private _hideSpinner(): void { // We wanna run this function outside of Angular's zone to // bypass change detection, this.ngZone.runOutsideAngular(() => { // For simplicity we are going to turn opacity on / off // you could add/remove a class for more advanced styling // and enter/leave animation of the spinner this.renderer.setElementStyle( this.spinnerElement.nativeElement, 'opacity', '0' ) }) } }
<div class="loading-overlay" #spinnerElement style="opacity: 0;"> <!-- md-spinner is short for <md-progress-circle mode="indeterminate"></md-progress-circle> --> <md-spinner></md-spinner> </div>