问题描述
在 Angular 2 中更改路线时如何显示加载屏幕?
当前的 Angular Router 提供了 Navigation Events.您可以订阅这些并相应地更改 UI.请记住计算其他事件,例如 NavigationCancel
和 NavigationError
以在路由器转换失败时停止您的微调器.
app.component.ts - 你的根组件
...进口 {路由器,//导入为 RouterEvent 以避免与 DOM 事件混淆事件作为 RouterEvent,导航开始,导航结束,导航取消,导航错误来自'@angular/router'@成分({})导出类 AppComponent {//将初始值设置为 true 以在第一次加载时显示加载微调器加载 = 真构造函数(私有路由器:路由器){this.router.events.subscribe((e : RouterEvent) => {this.navigationInterceptor(e);})}//在 RouterEvent 更改期间显示和隐藏加载微调器导航拦截器(事件:RouterEvent):无效{如果(导航开始的事件实例){this.loading = 真}如果(导航结束的事件实例){this.loading = false}//在以下两个事件中将加载状态设置为 false 以在请求失败时隐藏微调器如果(导航取消的事件实例){this.loading = false}如果(导航错误的事件实例){this.loading = false}}}app.component.html - 你的根视图
<!-- 在这里展示一些奇特的东西,这里是 Angular 2 Material 的加载条或圆--><md-progress-bar mode="indeterminate"></md-progress-bar>
性能改进答案:如果您关心性能,则有更好的方法,实施起来稍微有些乏味,但性能改进值得付出额外的努力.我们可以利用 Angular 的 NgZone
和 Renderer
来打开/关闭将绕过 Angular 的微调器,而不是使用 *ngIf
有条件地显示微调器当我们改变微调器的状态时改变检测.我发现与使用 *ngIf
或 async
管道相比,这可以使动画更流畅.
这与我之前的回答类似,但做了一些调整:
app.component.ts - 你的根组件
...进口 {路由器,//导入为 RouterEvent 以避免与 DOM 事件混淆事件作为 RouterEvent,导航开始,导航结束,导航取消,导航错误来自'@angular/router'从@angular/core"导入 {NgZone、Renderer、ElementRef、ViewChild}@成分({})导出类 AppComponent {//而不是持有一个布尔值来判断微调器是否//应该显示还是不显示,我们存储了一个对微调元素的引用,//请参阅此脚本下方的模板片段@ViewChild('spinnerElement')spinnerElement: ElementRef构造函数(私有路由器:路由器,私人 ngZone: NgZone,私人渲染器:渲染器){router.events.subscribe(this._navigationInterceptor)}//在 RouterEvent 更改期间显示和隐藏加载微调器私人_navigationInterceptor(事件:RouterEvent):无效{如果(导航开始的事件实例){//我们想在 Angular 的区域之外运行这个函数//绕过变化检测this.ngZone.runOutsideAngular(() => {//为简单起见,我们将打开/关闭不透明度//您可以添加/删除一个类以获得更高级的样式//和进入/离开微调器的动画this.renderer.setElementStyle(this.spinnerElement.nativeElement,'不透明度','1')})}如果(导航结束的事件实例){this._hideSpinner()}//在以下两个事件中将加载状态设置为 false//在请求失败时隐藏微调器如果(导航取消的事件实例){this._hideSpinner()}如果(导航错误的事件实例){this._hideSpinner()}}私人_hideSpinner():无效{//我们想在 Angular 的区域之外运行这个函数//绕过变化检测,this.ngZone.runOutsideAngular(() => {//为简单起见,我们将打开/关闭不透明度//您可以添加/删除一个类以获得更高级的样式//和进入/离开微调器的动画this.renderer.setElementStyle(this.spinnerElement.nativeElement,'不透明度','0')})}}app.component.html - 你的根视图
<!-- md-spinner 是 <md-progress-circle mode="indeterminate"></md-progress-circle> 的缩写.--><md-spinner></md-spinner>
How do I show a loading screen when I change a route in Angular 2?
The current Angular Router provides Navigation Events. You can subscribe to these and make UI changes accordingly. Remember to count in other Events such as NavigationCancel
and NavigationError
to stop your spinner in case router transitions fail.
app.component.ts - your root component
...
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 - your root view
<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>
Performance Improved Answer: If you care about performance there is a better method, it is slightly more tedious to implement but the performance improvement will be worth the extra work. Instead of using *ngIf
to conditionally show the spinner, we could leverage Angular's NgZone
and Renderer
to switch on / off the spinner which will bypass Angular's change detection when we change the spinner's state. I found this to make the animation smoother compared to using *ngIf
or an async
pipe.
This is similar to my previous answer with some tweaks:
app.component.ts - your root component
...
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 - your root view
<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>
这篇关于在 Angular 2 中的路线之间导航时显示加载屏幕的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!