Angular 2'de bir rotayı değiştirdiğimde nasıl bir yükleme ekranı gösterebilirim?
Angular 2'de bir rotayı değiştirdiğimde nasıl bir yükleme ekranı gösterebilirim?
Yanıtlar:
Mevcut Angular Router, Navigasyon Olayları sağlar. Bunlara abone olabilir ve buna göre UI değişiklikleri yapabilirsiniz. Gibi diğer Olaylar saymak unutmayın NavigationCancel
ve NavigationError
geçişler başarısız yönlendirici ihtimaline karşı değer değişimi durdurmak için.
app.component.ts - kök bileşeniniz
...
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 - kök görünümünüz
<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>
Performans İyileştirilmiş Cevap : Performansı önemsiyorsanız, daha iyi bir yöntem var, uygulamak biraz daha zahmetli ama performans iyileştirmesi fazladan çalışmaya değer. Bunun yerine kullanmanın *ngIf
şartlı değer değişimi göstermek için, biz Açısal en kaldıraç olabilir NgZone
ve Renderer
açısal değişim tespiti baypas Spinner'a durumunu değiştirecek spinner kapalı / açmak için. I kullanılmasına kıyasla animasyon daha yumuşak olması için bu bulundu *ngIf
ya da async
boru.
Bu, bazı ince ayarlarla önceki cevabıma benzer:
app.component.ts - kök bileşeniniz
...
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'
)
})
}
}
app.component.html - kök görünümünüz
<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>
router navigation
ve it triggering the spinner
ardından bunu durdurmak mümkün değil. navigationInterceptor
bir çözüm gibi görünüyor ama kırılmayı bekleyen başka bir şey olup olmadığından emin değilim. async requests
Onunla karıştırılırsa sorunu yeniden ortaya çıkaracağını düşünüyorum.
display
ya none
ya inline
.
'md-spinner' is not a known element:
. Angular'da oldukça yeniyim. Lütfen bana hatanın ne olabileceğini söyler misin?
GÜNCELLEME: 3 Yeni Yönlendiriciye yükseltme yaptığıma göre, @borislemke'nin yaklaşımı, CanDeactivate
koruma kullanırsanız işe yaramayacak . Eski yöntemime alçalıyorum, ie:
bu cevap
Update2 : Yeni-yönlendirici bir görünüm vaat ve Router olaylar cevap tarafından @borislemke spinner uygulamasının ana yönünü kapsayacak şekilde görünüyor, bunu test havent't ama ben bunu tavsiye.
UPDATE1: Bu cevabı şu çağda yazdım :Old-Router
route-changed
bildirilen tek bir olayrouter.subscribe()
. Ayrıca aşağıdaki yaklaşımın aşırı yüklendiğini hissettim ve sadece kullanarak yapmaya çalıştım router.subscribe()
ve geri tepti çünkü tespit etmenin bir yolu yoktu canceled navigation
. Bu yüzden uzun yaklaşıma geri dönmek zorunda kaldım (çift çalışma).
Angular2'de yolunuzu biliyorsanız, ihtiyacınız olan şey budur
Boot.ts
import {bootstrap} from '@angular/platform-browser-dynamic';
import {MyApp} from 'path/to/MyApp-Component';
import { SpinnerService} from 'path/to/spinner-service';
bootstrap(MyApp, [SpinnerService]);
Kök Bileşeni- (Uygulamam)
import { Component } from '@angular/core';
import { SpinnerComponent} from 'path/to/spinner-component';
@Component({
selector: 'my-app',
directives: [SpinnerComponent],
template: `
<spinner-component></spinner-component>
<router-outlet></router-outlet>
`
})
export class MyApp { }
Spinner-Bileşen (aktif değerini buna göre değiştirmek için Spinner hizmetine abone olacak)
import {Component} from '@angular/core';
import { SpinnerService} from 'path/to/spinner-service';
@Component({
selector: 'spinner-component',
'template': '<div *ngIf="active" class="spinner loading"></div>'
})
export class SpinnerComponent {
public active: boolean;
public constructor(spinner: SpinnerService) {
spinner.status.subscribe((status: boolean) => {
this.active = status;
});
}
}
Spinner-Service (bu hizmeti önyükleme)
Değişim durumunda durumu değiştirmek için eğirme bileşeni tarafından abone olunacak bir gözlemlenebilir tanımlayın ve eğiriciyi etkin / pasif hale getirmek için işlev ve işlev tanımlayın.
import {Injectable} from '@angular/core';
import {Subject} from 'rxjs/Subject';
import 'rxjs/add/operator/share';
@Injectable()
export class SpinnerService {
public status: Subject<boolean> = new Subject();
private _active: boolean = false;
public get active(): boolean {
return this._active;
}
public set active(v: boolean) {
this._active = v;
this.status.next(v);
}
public start(): void {
this.active = true;
}
public stop(): void {
this.active = false;
}
}
Diğer Tüm Rotaların Bileşenleri
(örneklem):
import { Component} from '@angular/core';
import { SpinnerService} from 'path/to/spinner-service';
@Component({
template: `<div *ngIf="!spinner.active" id="container">Nothing is Loading Now</div>`
})
export class SampleComponent {
constructor(public spinner: SpinnerService){}
ngOnInit(){
this.spinner.stop(); // or do it on some other event eg: when xmlhttp request completes loading data for the component
}
ngOnDestroy(){
this.spinner.start();
}
}
spinner-service
Şimdilik bazı kodlar ekledim , çalışmasını sağlamak için sadece diğer bölümlere ihtiyacınız var. Ve unutmayınangular2-rc-1
Neden sadece basit css kullanmıyorsunuz:
<router-outlet></router-outlet>
<div class="loading"></div>
Ve tarzınızda:
div.loading{
height: 100px;
background-color: red;
display: none;
}
router-outlet + div.loading{
display: block;
}
Veya bunu ilk cevap için bile yapabiliriz:
<router-outlet></router-outlet>
<spinner-component></spinner-component>
Ve sonra sadece
spinner-component{
display:none;
}
router-outlet + spinner-component{
display: block;
}
Buradaki hile, yeni rotalar ve bileşenlerin her zaman yönlendirici çıkışından sonra görüneceğidir , bu nedenle basit bir css seçici ile yüklemeyi gösterebilir ve gizleyebiliriz.
İlk rota için gerekli özel mantığınız varsa, yalnızca aşağıdakileri yapabilirsiniz:
loaded = false;
constructor(private router: Router....) {
router.events.pipe(filter(e => e instanceof NavigationEnd), take(1))
.subscribe((e) => {
this.loaded = true;
alert('loaded - this fires only once');
});
Buna, sayfanın üst kısmında görünen sayfa alt bilgimi gizlemek için bir ihtiyacım vardı. Ayrıca, yalnızca ilk sayfa için bir yükleyici istiyorsanız, bunu kullanabilirsiniz.
Bu mevcut çözümü de kullanabilirsiniz . Demo burada . Youtube yükleme çubuğuna benziyor. Yeni buldum ve kendi projeme ekledim.