Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angular/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/batch-file/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 显示导航加载器微调器,角度为2+;_Javascript_Angular_Rxjs_Ngrx Store - Fatal编程技术网

Javascript 显示导航加载器微调器,角度为2+;

Javascript 显示导航加载器微调器,角度为2+;,javascript,angular,rxjs,ngrx-store,Javascript,Angular,Rxjs,Ngrx Store,我是angular 2+和RxJS的新手,尝试适应RxJS 我会在路线转换上显示load spinner,但前提是它所花费的时间超过一定的时间,LAT表示为160ms 我有一个加载微调器作为一个单独的组件,它订阅了ngrx存储,因此我根据sore中的值显示/隐藏加载微调器(showSpinner) 在我的应用程序根组件中,我订阅路由器更改事件,并分派操作(显示\u微调器/隐藏\u微调器) 所以问题是,有没有更简单的方法来实现它 下面是我的部分代码 .... export const navig

我是angular 2+和RxJS的新手,尝试适应RxJS

我会在路线转换上显示load spinner,但前提是它所花费的时间超过一定的时间,LAT表示为160ms
我有一个加载微调器作为一个单独的组件,它订阅了ngrx存储,因此我根据sore中的值显示/隐藏加载微调器(showSpinner)

在我的应用程序根组件中,我订阅路由器更改事件,并分派操作(显示\u微调器/隐藏\u微调器)
所以问题是,有没有更简单的方法来实现它

下面是我的部分代码

....

export const navigationStreamForSpinnerStatuses = {
  NAVIGATION_STARTED: 'NAVIGATION_STARTED',
  NAVIGATION_IN_PROGRESS: 'NAVIGATION_IN_PROGRESS',
  NAVIGATION_ENDED: 'NAVIGATION_ENDED'
};

私人导航开始流;
私人航行延迟开始;
私人导航FinishStream;
构造函数(专用存储:存储,专用路由器:路由器){
this.navigationStartStream=router.events
.filter(事件=>{
返回NavigationStart的事件实例;
})
.map(()=>NavigationStreamForSpinnerStatus.NAVIGATION_已启动);
this.navigationStartStreamWithDelay=this.navigationStartStream
.延迟(160)
.map(()=>NavigationStreamForSpinnerStatus.NAVIGATION正在进行中);
this.navigationFinishStream=router.events
.filter(事件=>{
返回NavigationEnd的事件实例| | NavigationCancel的事件实例| | NavigationError的事件实例;
})
.map(()=>NavigationStreamForSpinnerStatus.NAVIGATION_结束);
这是一条名为navigationStartStream的河流
.merge(此.navigationFinishStream)
.merge(此.navigationStartStreamWithDelay)
.成对
.订阅([previousStatus,currentStatus]=>{
if(previousStatus!==NavigationStreamForSpinnerStatus.NAVIGATION\u已结束和¤tStatus==NavigationStreamForSpinnerStatus.NAVIGATION\u正在进行){
this.store.dispatch({type:StateLoaderSpinnerActionsTypes.SHOW_SPINNER});
}else if(previousStatus==navigationStreamForSpinnerStatuses.NAVIGATION\u正在进行中和currentStatus==navigationStreamForSpinnerStatuses.NAVIGATION\u已结束){
this.store.dispatch({type:stateLoaderPinnerActionStypes.HIDE_SPINNER});
}
});
}

如果微调器计时器在时间之前返回,请使用
takeUntil
操作符取消微调器计时器。此外,使用
计时器创建热可观察对象,以在特定时间过后触发操作

takeUntil
返回源可观察序列中的值,直到另一个可观察序列或承诺生成值

timer
返回一个可观察序列,该序列在dueTime结束后以及每个时段结束后生成一个值

您可以通过直接在每个流上处理分派来简化您的逻辑

this.navigationEnd$ = router.events
  .filter(event => event instanceof NavigationEnd || event instanceof NavigationCancel || event instanceof NavigationError);

this.navigationStart$ = router.events
  .filter(event => event instanceof NavigationStart)
  .subscribe(_ => {
    Observable.timer(160)
      .takeUntil(this.navigationEnd$)
      .subscribe(_ => this.store.dispatch({ type: StateLoaderSpinnerActionsTypes.SHOW_SPINNER });
  });

this.navigationEnd$.subscribe(_ => this.store.dispatch({ type: StateLoaderSpinnerActionsTypes.HIDE_SPINNER });

因此,我们所做的是收听导航的开始,并启动一个
计时器
160毫秒。如果导航结束事件发生在计时器之前,则不会显示微调器(
takeUntil
)。否则,将调度存储操作并显示微调器。无论是否显示微调器,在导航完成后,我们都会调度隐藏微调器操作

我的方法是基于Http请求,这可能不适用于所有情况,因为有些应用程序只使用WebSocket,或者根本不使用外部请求。但对于一大组应用程序,他们通过HttpClient(angular 4.3+)获取所有数据。我写了一个HttpInterceptor就是这样做的

import { HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from '@angular/common/http'
import { Inject, Injectable, RendererFactory2 } from '@angular/core'
import { Observable, timer } from 'rxjs'
import { filter, takeUntil, tap } from 'rxjs/operators'
import { DOCUMENT } from '@angular/common'

const reqIsSpinnable = (req: HttpRequest<any>) => {
  return req.url.includes('api/')
}

@Injectable()
export class HttpSpinnerInterceptor implements HttpInterceptor {
  constructor(@Inject(DOCUMENT) private doc: HTMLDocument, private rdf: 
    RendererFactory2) { }

  // tslint:disable-next-line:no-null-keyword
  readonly rdr = this.rdf.createRenderer(null, null)

  get spinnerElement() {
    return this.doc.querySelector('#core-spin')
  }

  startSpin() {
    this.rdr.setStyle(this.spinnerElement, 'display', 'block')
  }

  closeSpin() {
    this.rdr.setStyle(this.spinnerElement, 'display', 'none')
  }

  intercept(req: HttpRequest<any>, next: HttpHandler):
    Observable<any> {
    const responseTimer$ = next.handle(req).pipe(filter(e => e instanceof HttpResponse))
    timer(120).pipe(takeUntil(responseTimer$)).subscribe(() => this.startSpin())

    return next.handle(req).pipe(tap(evt => {
      if (reqIsSpinnable(req) && evt instanceof HttpResponse) {
        this.closeSpin()
      }
    }))
从'@angular/common/http'导入{HttpHandler,HttpInterceptor,HttpRequest,HttpResponse}
从“@angular/core”导入{Inject,Injectable,renderFactory2}
从“rxjs”导入{Observable,timer}
从'rxjs/operators'导入{filter,takeUntil,tap}
从“@angular/common”导入{DOCUMENT}
常量请求可扩展=(请求:HttpRequest)=>{
返回请求url.includes('api/'))
}
@可注射()
导出类HttpSpinnerInterceptor实现HttpInterceptor{
构造函数(@Inject(DOCUMENT)private doc:HTMLDocument,private rdf:
渲染器工厂2){}
//tslint:禁用下一行:无空关键字
只读rdr=this.rdf.createRenderer(null,null)
获取spinnerElement(){
返回此.doc.querySelector(“#核心旋转”)
}
startSpin(){
this.rdr.setStyle(this.spinnerElement'display','block')
}
closeSpin(){
this.rdr.setStyle(this.spinnerElement'display','none')
}
拦截(请求:HttpRequest,下一步:HttpHandler):
可观察{
const responseTimer$=next.handle(req.pipe)(过滤器(e=>e HttpResponse实例))
计时器(120).pipe(takeUntil(responseTimer$).subscribe(()=>this.startSpin())
返回next.handle(req).pipe(tap(evt=>{
if(HttpResponse的可请求(req)和evt实例){
this.closeSpin()
}
}))
}
}

它有什么帮助?在navigationStartStream发出后,它不会用延迟流取消整个navigationStartStream吗?@MykhailoI抱歉,我试图不做太多更改。请看我上面做的编辑,如果更清楚的话,请告诉我。谢谢,很清楚。我只是想知道,如果SHOW\u微调器未被调度,是否有办法不调度HIDE\u微调器?我想重构我的load spinner,稍后,使其通用,以便我可以将其用于其他网络请求,我正在考虑在存储中添加一些计数器,并且仅当计数器为零时才将showSpinner更改为false,因此在没有之前的SHOW spinner的情况下,额外的HIDE_spinner调度将打破这种逻辑,我必须在store中引入一些属性来区分网络负载微调器和路由负载微调器或其他workaround@MykhailoI您可以在
navigationEnd$
流中添加一个过滤器,用于检查微调器当前是否显示。
import { HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from '@angular/common/http'
import { Inject, Injectable, RendererFactory2 } from '@angular/core'
import { Observable, timer } from 'rxjs'
import { filter, takeUntil, tap } from 'rxjs/operators'
import { DOCUMENT } from '@angular/common'

const reqIsSpinnable = (req: HttpRequest<any>) => {
  return req.url.includes('api/')
}

@Injectable()
export class HttpSpinnerInterceptor implements HttpInterceptor {
  constructor(@Inject(DOCUMENT) private doc: HTMLDocument, private rdf: 
    RendererFactory2) { }

  // tslint:disable-next-line:no-null-keyword
  readonly rdr = this.rdf.createRenderer(null, null)

  get spinnerElement() {
    return this.doc.querySelector('#core-spin')
  }

  startSpin() {
    this.rdr.setStyle(this.spinnerElement, 'display', 'block')
  }

  closeSpin() {
    this.rdr.setStyle(this.spinnerElement, 'display', 'none')
  }

  intercept(req: HttpRequest<any>, next: HttpHandler):
    Observable<any> {
    const responseTimer$ = next.handle(req).pipe(filter(e => e instanceof HttpResponse))
    timer(120).pipe(takeUntil(responseTimer$)).subscribe(() => this.startSpin())

    return next.handle(req).pipe(tap(evt => {
      if (reqIsSpinnable(req) && evt instanceof HttpResponse) {
        this.closeSpin()
      }
    }))