2

快速上下文:我正在显示“实时”图像幻灯片,这意味着在显示图像时,用户可以上传图像并且这些新图像应该显示(最终)。这是“无限的”,这意味着一旦发出所有图像,我想从第一张图像重新开始。新传入的图像应该排在队列的末尾并在我循环回它们时发出。

我想出了一个我认为是肮脏和不正确的解决方案,归结为:

const srcArray = [-2, -1];
const userImageUpload$ = interval(2000).pipe(
  tap((val) => srcArray.push(val))
).subscribe();

const liveImages$ = zip(interval(1000), from(srcArray)).pipe(
  map(([a, b]) => b),
  repeat()
).subscribe((val) => console.log("Image " + val));

这里我们有一些“图像”的起始数组。userImageUpload$代表新图像传入的想法。当我得到一个时,我将它推入起始数组。liveImages$表示我想要发出的值。这在技术上是可行的,但是改变这个共享的全局数组感觉很糟糕,并且可能会导致问题。是否有一个很好的解决方案可以将这一切合二为一,可能使用主题?我很难想出一个解决方案。

4

3 回答 3

2

我会保留一个currentImages$可观察的来累积所有上传的图像,以及一个currentImageIndex$可观察的来保留当前应该显示的图像的索引。那么liveImagesObservable (结合了两者)就是你想要的结果。

const currentImages$ = userImageUpload$.pipe(
    scan((acc, curr) => [...acc, curr], [])
);

const currentImageIndex$ = interval(SLIDE_SHOW_INTERVAL).pipe(
    withLatestFrom(currentImages$),
    map(([, currImages]) => currImages),
    scan((accIndex, currImagesArr) => (accIndex + 1) % currImagesArr.length, 0)
);

const liveImages$ = currentImageIndex$.pipe(
    withLatestFrom(currentImages$),
    map(([currIndex, currImages]) => currImages[currIndex])
);
于 2020-11-10T11:34:47.857 回答
0

使用BehaviorSubject更有意义。我认为您的解决方案很好,此答案的不同之处在于,您会在上传图像时收到通知,即数组更新,通过使用imageStore.

const imageStore=new BehaviorSubject([-2, -1]);

const userImageUpload$ = interval(2000).pipe(
  map((val) => imageStore.getValue().concat(val))
).subscribe(imageStore);

imageStore.pipe(switchMap(srcArray=>
 zip(interval(1000), from(srcArray)).pipe(
   map(([a, b]) => b),
   repeat()
  )
))
于 2020-11-10T05:36:46.140 回答
0

您可以这样尝试,您可以在我的 stackblitz(Angular 示例)中看到相同的内容 https://stackblitz.com/edit/angular-ivy-dhvt8r?file=src/app/app.component.html

private images: BehaviorSubject<number[]> = new BehaviorSubject<number[]>([
    -2,
    -1
  ]);
  private imagesChanged$ = this.images.asObservable();

  imageToDisplay$: Observable<number>;

  ngOnInit() {
    this.imageToDisplay$ = this.imagesChanged$.pipe(
      switchMap(() => interval(1000)),
      map((v: number) => v % this.images.value.length),
      map((v: number) => this.images.value[v])
    );
  }

  addImage() {
    this.images.next([
      ...this.images.value,
      this.images.value[this.images.value.length - 1] + 1
    ]);
  }
<div>
    Current Image: {{ imageToDisplay$ | async }}
</div>

<button (click)="addImage()">Add a Image</button>
于 2020-11-10T08:14:41.900 回答