javascript - 在 Angular 中单击时重置 rxjs 间隔

标签 javascript angular typescript rxjs rxjs6

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

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

这是我得到的:

  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;
    }
  }

模板:

<div class="sliderNav">
    <mat-icon (click)="slide('back')">keyboard_arrow_up</mat-icon>
    <p>{{currentSlide + 1}}/{{SLIDES.length}}</p>
    <mat-icon (click)="slide('forward')">keyboard_arrow_down</mat-icon>
</div>

最佳答案

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

方案一: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(此处所示)之类的多播可观察对象或使用带有 fromEvent 函数的模板引用变量(未显示)来获取用户的手动输入.
  2. 使用 switchMap 运算符将一个可观察量映射到另一个可观察量。当外部可观察对象发出时,switchMap 取消/关闭内部可观察对象。这样计时器就会重新生成。
  3. ngOnDestroy() Hook 中关闭订阅,以避免打开的订阅造成内存泄漏。此处使用 takeUntil 运算符进行说明。

Controller (*.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>

关于javascript - 在 Angular 中单击时重置 rxjs 间隔,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68174823/

相关文章:

css - :first-child with *ngFor is not working properly

angular - 使用 VSCode 调试 Typescript Protractor 测试

javascript - 函数不识别变量

javascript - 选中/取消选中 parent 和 child

javascript - 在文件上传时隐藏 span 元素

typescript - 构建 : '(' expected in *. d.ts 文件。无法编译 TypeScript 项目

javascript - 循环遍历 Observable 数据,推送到数组,并显示数组 typescript 的所有结果

javascript - 在下拉选择中显示 Bootstrap 模式

javascript - 如何替换 Angular 2中的字符串?

angular - 如何使用 float 标签进行 ionic 选择