angular 带幻灯片的旋转木马,点击圆点按钮后重置,使用 rxjs

angular carousel with slide show, reset after clicking on dot button, using rxjs

工作 示例在此 Stackblitz Link

我正在使用 rxjs 构建 angular 旋转木马滑块更改组件。 5 秒后更换每张载玻片。目前睡得很好。但我的问题是,当单击 dot-button 时,同一个单击的点幻灯片会返回并显示该幻灯片,但下一个更改不是从上一个单击的位置开始的,以检测我在上面的堆栈闪电战中所说的内容 link 如果您单击任何点,则下一张幻灯片不会从单击的位置开始。我目前正在做的事情如下所示..

export class AppComponent {
   dotsLength;

   selectedDotIndexSubject = new BehaviorSubject<number>(undefined);
   selectedDotIndexSubject$ = this.selectedDotIndexSubject
   .asObservable()
   .pipe(
         switchMap(index => concat(of(index), of(undefined).pipe(delay(5000))))
    );

   readonly currentIndex$ = range(1, 3).pipe(
      concatMap(value => of(value).pipe(delay(5000))),
      repeat()
   );

   mainSlider$ = combineLatest([
       this.selectedDotIndexSubject$,
       this.currentIndex$
   ]).pipe(
          map(([selectedIndex, autoIndex]) => {
              return selectedIndex ?? autoIndex;
          })
    );
   readonly images = ["6027869", "3889926", "6027869"];
    ngOnInit() {
       this.dotsLength = new Array(this.images.length).fill(0);
    }
    dotClick(index: any) {
       this.selectedDotIndexSubject.next(index);
    }
}

如上代码所示,我正在组合两个 rxjs 流,一个是点击主题,另一个是 range() 运算符和 repeat() 运算符。

这里是组件的模板文件

<ng-container *ngIf="mainSlider$ | async as currentIndex">
    <h2>Automatic Slideshow</h2>
       {{currentIndex}}
            <p>Change image every 2 seconds:</p>
        <div class="slideshow-container">
           <div *ngFor="let image of images; let i = index;" class="mySlides fade" [class.active]="i === currentIndex - 1">
           <div class="numbertext">{{ i + 1 }} / {{ images.length }}</div>
        <img
    [src]="'https://images.pexels.com/photos/' + image + '/pexels-photo-' + image + '.jpeg'">
        <div class="text">
            Caption {{ i + 1 }}
        </div>
    </div>
</div>

<br>
<div style="text-align:center">
    <span *ngFor="let dots of dotsLength; let i = index;"
    [class.active]="currentIndex - 1  === i"
    #dot
    (click)="dotClick(i + 1)"
    class="dot">
 </span>
 </div>

 </ng-container> 

你的计数没有恢复的原因是当你点击时计数器没有被重置。所以它立即使用点击的索引,然后返回到下一个。

在手动点击一个点时让计数器重置的最简单方法可能是启动一个以稳定间隔发射的新 Observable。

您可以使用单个 BehaviorSubject 来发出点击点的索引,它可用于生成一个新的可观察对象,该观察对象以从该索引值开始的时间间隔发出。

  selectedIndexSubject = new BehaviorSubject<number>(0);

  currentIndex$ = this.selectedIndexSubject.pipe(
    switchMap(selectedIndex => timer(0, 2000).pipe(
      map(tick => (tick + selectedIndex) % this.imageIds.length)
    ))
  );

  dotClick(index: number) {
    this.selectedIndexSubject.next(index);
  }

我注意到您在模板中使用了基于 1 的索引,而在控制器中使用了基于 0 的索引。我发现总是使用基于 0 的更容易。我知道 *ngIf 在解包值是假的 (0) 时会导致问题,因为它会在索引 = 0 时隐藏您的模板。

有一种我喜欢使用的技术可以很好地克服这个问题,那就是向您的视图公开一个可观察对象,该对象包含您的视图所需的所有数据。这样,对象永远不会是假的,并且任何恰好是 0 的值都可以轻松访问。

这是一个有效的 StackBlitz