如何在 Angular 中实现全局加载器 [英] How to implement a global loader in Angular

查看:41
本文介绍了如何在 Angular 中实现全局加载器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个全局加载器,它是这样实现的:

I have a global loader which is implemented like this:

核心模块:

router.events.pipe(
  filter(x => x instanceof NavigationStart)
).subscribe(() => loaderService.show());

router.events.pipe(
  filter(x => x instanceof NavigationEnd || x instanceof NavigationCancel || x instanceof NavigationError)
).subscribe(() => loaderService.hide());

加载服务:

@Injectable({
    providedIn: 'root'
})
export class LoaderService {

    overlayRef: OverlayRef;
    componentFactory: ComponentFactory<LoaderComponent>;
    componentPortal: ComponentPortal<LoaderComponent>;
    componentRef: ComponentRef<LoaderComponent>;

    constructor(
        private overlay: Overlay,
        private componentFactoryResolver: ComponentFactoryResolver
    ) {
        this.overlayRef = this.overlay.create(
            {
                hasBackdrop: true,
                positionStrategy: this.overlay.position().global().centerHorizontally().centerVertically()
            }
        );

        this.componentFactory = this.componentFactoryResolver.resolveComponentFactory(LoaderComponent);

        this.componentPortal = new ComponentPortal(this.componentFactory.componentType);
    }

    show(message?: string) {
        this.componentRef = this.overlayRef.attach<LoaderComponent>(this.componentPortal);
        this.componentRef.instance.message = message;
    }

    hide() {
        this.overlayRef.detach();
    }
}

使用 Angular 7.0.2 运行时,行为(我想要的)是:

When running with Angular 7.0.2, the behavior (which I wanted) was:

  • 在解析附加到路由的数据和加载惰性模块时显示加载器
  • 导航到没有任何解析器的路由时不显示加载程序

我已经更新到 Angular 7.2,现在的行为是:

I have updated to Angular 7.2, now the behavior is:

  • 在解析附加到路由的数据和加载惰性模块时显示加载器
  • 导航到没有任何解析器的路由时,显示没有 LoaderComponent 的 Overlay
  • Show loader while resolving data attached to a route, and while loading a lazy module
  • Show the Overlay whithout the LoaderComponent when navigating to a route without any resolver

我在 NavigationStartNavigationEnd 事件上添加了一些日志,我发现 NavigationEndNavigationStart 之后立即触发code>(这是正常的),而Overlay在大约0.5s后消失.

I have added some logs on the NavigationStart and NavigationEnd events and I found that NavigationEnd is triggered immediately after NavigationStart (which is normal), while Overlay disappears about 0.5s after.

我已经阅读了 CHANGELOG.md 但我没有发现任何可以解释这个问题的内容.欢迎提出任何想法.

I have read the CHANGELOG.md but I found nothing that might explain this problem. Any idea is welcome.

经过进一步研究,我通过如下设置 package.json 恢复了以前的行为:

After further research, I have restored the previous behavior by setting package.json like this:

"@angular/cdk": "~7.0.0",
"@angular/material": "~7.0.0",

而不是这个:

"@angular/cdk": "~7.2.0",
"@angular/material": "~7.2.0",

我已经确定了在 7.1.0 版本中发布的错误提交,并将我的问题发布到相关的 GitHub 问题.它修复了 Overlay 的淡出动画.

I have identified the faulty commit which has been released in version 7.1.0 and I posted my problem on the related GitHub issue. It fixes the fade out animation of the Overlay.

获得所需行为的符合 v7.1+ 的方法是什么?在我看来,最好的做法是:仅在必要时显示加载程序,但 NavigationStart 不包含所需的信息.我想避免最终出现一些去抖动行为.

What is the v7.1+ compliant way to get the desired behavior? According to me, the best thing to do would be: show the loader only when necessary, but NavigationStart doesn't hold the needed information. I'd like to avoid ending up with some debounce behavior.

推荐答案

这是我在意识到 delay 在 UX 方面是一个很好的解决方案之后得到的结果,因为它允许加载器仅在加载时间值得显示加载器时显示.

Here is what I ended up with, after realizing that a delay was a good solution in terms of UX because it allowed the loader to show only when the loading time is worth displaying a loader.

我不喜欢这个解决方案,因为它意味着在两个 Observables 之间共享一个状态,而 Observables 是关于纯管道而不是副作用和共享状态.

I don't like this solution because it implies to share a state between two Observables, when Observables are about pure pipes rather than side effects and shared states.

counter = 0;

router.events.pipe(
  filter(x => x instanceof NavigationStart),
  delay(200),
).subscribe(() => {
  /*
  If this condition is true, then the event corresponding to the end of this NavigationStart
  has not passed yet so we show the loader
  */
  if (this.counter === 0) {
    loaderService.show();
  }
  this.counter++;
});

router.events.pipe(
  filter(x => x instanceof NavigationEnd || x instanceof NavigationCancel || x instanceof NavigationError)
).subscribe(() => {
  this.counter--;
  loaderService.hide();
});

这篇关于如何在 Angular 中实现全局加载器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆