Angular 2에서 경로 간 이동 시 로딩 화면 표시
Angular 2에서 경로를 변경할 때 로드 화면을 표시하려면 어떻게 해야 합니까?
현재 각도 라우터는 탐색 이벤트를 제공합니다.이 항목에 가입하고 그에 따라 UI를 변경할 수 있습니다.다음과 같은 다른 이벤트에서 계산하는 것을 기억하십시오.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.vmdk - 루트 보기
<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
조건부로 스피너를 보여주기 위해 앵귤러의NgZone
그리고.Renderer
스피너의 상태를 변경할 때 Angular의 변경 감지를 무시하는 스피너를 켜거나 끕니다.저는 이것을 사용하는 것보다 애니메이션을 더 부드럽게 만들기 위해 찾았습니다.*ngIf
또는async
파이프를 피우다
이것은 제가 이전에 몇 가지 수정을 한 답변과 비슷합니다.
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'
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.vmdk - 루트 보기
<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>
업데이트:3 이제 새 라우터로 업그레이드했으므로, 사용하면 @borislemke의 접근 방식이 작동하지 않습니다.CanDeactivate
경비원입니다 예전 방식으로 품위를 떨어뜨리고 있어요ie:
이 대답
업데이트 2:새로운 라우터의 라우터 이벤트는 유망해 보이고 @borislemke의 답변은 스피너 구현의 주요 측면을 다루는 것 같습니다. 테스트하지 않았지만 추천합니다.
업데이트 1:나는 이 대답을 의 시대에 썼습니다.Old-Router
예전에는 단 하나의 사건이 있었을 때.route-changed
을 통해 통지된.router.subscribe()
저도 아래의 접근법에 과부하를 느껴서 그것을 오직 사용하여 하려고 했습니다.router.subscribe()
그리고 그것은 역효과를 낳았습니다. 왜냐하면 그것을 감지할 방법이 없었기 때문입니다.canceled navigation
그래서 저는 다시 긴 접근법(이중 작업)으로 돌아가야 했습니다.
Angular2에서 당신의 길을 안다면, 이것이 당신이 필요로 하는 것입니다.
부트.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]);
루트 구성 요소 - (MyApp)
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-Component(Spinner-service에 가입하여 활성 값을 적절히 변경)
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(이 서비스를 부트스트랩)
스피너 구성 요소가 변경 시 상태를 변경할 수 있는 관찰 가능한 항목을 정의하고 스피너를 알고 활성/비활성으로 설정하는 기능을 수행합니다.
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;
}
}
다른 모든 경로의 구성 요소
(샘플):
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();
}
}
단순한 CSS를 사용하는 것이 어때요?
<router-outlet></router-outlet>
<div class="loading"></div>
그리고 당신의 스타일로:
div.loading{
height: 100px;
background-color: red;
display: none;
}
router-outlet + div.loading{
display: block;
}
또는 첫 번째 대답에 대해서도 이렇게 할 수 있습니다.
<router-outlet></router-outlet>
<spinner-component></spinner-component>
그리고 간단히 말하면,
spinner-component{
display:none;
}
router-outlet + spinner-component{
display: block;
}
여기서 비결은 새로운 경로와 구성 요소가 항상 라우터 콘센트 뒤에 나타나므로 간단한 CSS 선택기로 로드를 표시하고 숨길 수 있다는 것입니다.
첫 번째 경로에만 특수 논리가 필요한 경우 다음을 수행할 수 있습니다.
앱 구성 요소
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');
});
페이지 맨 위에 표시되는 내 페이지 바닥글을 숨기기 위해 필요했습니다.또한 첫 페이지에만 로더를 사용하려는 경우 이 기능을 사용할 수 있습니다.
이 기존 솔루션을 사용할 수도 있습니다.데모가 왔습니다.유튜브 로딩바 같아요.저는 방금 그것을 찾아서 제 프로젝트에 추가했습니다.
언급URL : https://stackoverflow.com/questions/37069609/show-loading-screen-when-navigating-between-routes-in-angular-2
'itsource' 카테고리의 다른 글
기존 ENUM 유형에 새 값 추가 (0) | 2023.05.27 |
---|---|
MongoDB: 배열 일치 매개변수에서 하위 문서 찾기 (0) | 2023.05.22 |
ES6 모듈을 사용하는 경우 Node.js의 __dirname에 대한 대안 (0) | 2023.05.22 |
Git vs Team Foundation 서버 (0) | 2023.05.22 |
--save와 --save-dev의 차이점은 무엇입니까? (0) | 2023.05.22 |