微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在 Angular 中单击时重置 rxjs 间隔 选项 1:JS setTimeout()选项 2:RxJS interval()

如何解决在 Angular 中单击时重置 rxjs 间隔 选项 1:JS setTimeout()选项 2:RxJS interval()

一个关于 RxJS 中间隔的简单问题 - 我制作了一个轮播图,幻灯片每分钟都在变化,有一个细节让我不满意。当用户手动将幻灯片切换到下一个或上一个时 - 间隔仍会自动更改幻灯片,但无论何时,直到间隔触发新值,因此它会忽略用户所做的任何事情。如何让间隔知道用户是否更改了幻灯片,并且仅从用户操作算一分钟,然后自动更改幻灯片。其他时间间隔应该自动正常工作。

很高兴听到想法,谢谢!!!

这是我得到的:

nodeGreen.getPeds(),p->node.contains(p.getX(),p.getY())

模板:

  source = interval(10000);

  ngOnInit(): void {
    this.source.subscribe(() => this.slide('forward'));
  }

  slide(option): void {
    switch (option) {
      case 'forward':
        this.currentSlide === this.SLIDES.length - 1 ?
          this.currentSlide = DEFAULT_SLIDE : this.currentSlide++;
        break;
      case 'back':
        this.currentSlide === DEFAULT_SLIDE ?
          this.currentSlide = this.SLIDES.length - 1 : this.currentSlide--;
        break;
    }
  }

解决方法

我会说 RxJS 对于这种行为来说太过分了。可以使用普通的 JS setTimeout() 函数来实现。此外,您不会在组件被销毁时关闭订阅,这可能会导致内存泄漏。

选项 1:JS setTimeout()

timeoutId: number;

ngOnInit(): void {
  this.resetTimer();      // <-- start timer when the component is created
}

resetTimer() {
  if (!!this.timeoutId) {             // <-- Update: clear the timeout
    clearTimeout(this.timeoutId);
  }
  this.timeoutId = setTimeout(() => this.slide('forward'),10000);
}

/**
 * Reset the timer each time `slide()` function is triggered:
 *   1. When the `setTimeout()` triggers the callback
 *   2. When the user changes the slide manually
 */
slide(option): void {
  this.resetTimer();       // <-- reset timer here

  switch (option) {
    case 'forward':
      this.currentSlide === this.SLIDES.length - 1 ?
        this.currentSlide = DEFAULT_SLIDE : this.currentSlide++;
      break;
    case 'back':
      this.currentSlide === DEFAULT_SLIDE ?
        this.currentSlide = this.SLIDES.length - 1 : this.currentSlide--;
      break;
  }
}

ngOnDestroy() {
  clearTimeout(this.timeoutId);      // <-- clear the timeout when the component is destroyed
}

选项 2:RxJS interval()

如果你坚持使用 RxJS,你需要考虑很多事情

  1. 使用 ReplaySubject 等多播 observable(此处显示)或使用带有 fromEvent 函数的模板引用变量(未显示)获取用户的手动输入。
  2. 使用 switchMap 运算符将一个可观察对象映射到另一个可观察对象。 switchMap 在外部 observable 发出时取消/关闭内部 observable。这样计时器就会重新生成。
  3. ngOnDestroy() 挂钩中关闭订阅以避免打开订阅导致内存泄漏。此处使用 takeUntil 运算符进行说明。

控制器 (*.ts)

import { ReplaySubject } from 'rxjs';
import { map,switchMap,takeUntil } from 'rxjs/operators';

clickEvents$ = new ReplaySubject<string>(1);   // <-- buffer 1
closed$ = new ReplaySubject<any>(1);

ngOnInit() {
  this.clickEvents$.asObservable.pipe(
    switchMap((event: string) => interval(10000).pipe(    // <-- cancel inner subscription when outer subscription emits
      map(() => event)                         // <-- map back to the event
    )),takeUntil(this.closed$)
  ).subscribe(this.slide.bind(this));          // <-- use `bind()` to preserve `this` in callback
}

slide(option): void {
  switch (option) {
    case 'forward':
      this.currentSlide === this.SLIDES.length - 1 ?
        this.currentSlide = DEFAULT_SLIDE : this.currentSlide++;
      break;
    case 'back':
      this.currentSlide === DEFAULT_SLIDE ?
        this.currentSlide = this.SLIDES.length - 1 : this.currentSlide--;
      break;
  }
}

ngOnDestroy() {
  this.closed$.next();                          // <-- close open subscriptions
}

模板 (*.html)

<button (click)="clickEvent$.next('back')">Back</button>
<button (click)="clickEvent$.next('forward')">Forward</button>
,

使用 RxJS 合并流

一种可能的解决方案是从按钮点击事件创建流并将它们合并在一起。

然后您可以使用 switchMap 每次源发出时重置间隔。这可能是这样的。

<div class="sliderNav">
    <mat-icon #slideBack>keyboard_arrow_up</mat-icon>
    <p>{{currentSlide + 1}}/{{SLIDES.length}}</p>
    <mat-icon #slideForward>keyboard_arrow_down</mat-icon>
</div>

intervalTime = 10000;

@ViewChild('slideBack',{static: true}) 
slideBack: ElementRef;

@ViewChild('slideForward',{static: true}) 
slideForward: ElementRef;

ngOnInit(): void {

  const [first$,forward$,interval$] = [
    timer(intervalTime),fromEvent(slideForward,'click'),interval(intervalTime)
  ].map(v => v.pipe(
    mapTo("forward")
  ));

  const backward$ = fromEvent(slideBack,'click').pipe(
    mapTo("backward")
  );

  merge(first$,backward$).pipe(
    switchMap(option => interval$.pipe(
      startWith(option)
    ))
  ).subscribe(option => {

    switch (option) {
      case 'forward':
        this.currentSlide === this.SLIDES.length - 1 ?
          this.currentSlide = DEFAULT_SLIDE : this.currentSlide++;
        break;
      case 'backward':
        this.currentSlide === DEFAULT_SLIDE ?
          this.currentSlide = this.SLIDES.length - 1 : this.currentSlide--;
        break;
    }

  })
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。