0

假设我有一个汽车清单:

const cars: Array<{carId: number}> = [{carId: 1}, {carId: 2}];

我在模板中渲染它们:

<div *ngFor=“let car of cars”&gt;</div>

在该模板内部,我想从返回可观察对象的方法中获取一些动态图像路径:

<div *ngFor=“let car of cars”&gt;
    <img [src]=“getImagePath(car) | async”&gt;
</div>

getImagePath(car: {carId: number}): Observable<string> {
   return //some service request that brings back a url based on the carId
}

对于状态管理和存储,我使用的是 Firebase。我所有的图像都存储在一个存储桶中,我可以通过为我的服务提供一个 carId 来获取它们,该 carId 使用它来获取下载 URL。

我想避免在第一次保存文件时使用 downloadURL 更新 Firestore,因为我会将它们存储在子集合中,并且由于 Firestore 的性质,将它们从那里拉出来已经很痛苦。

有没有办法更有效地做到这一点?如果列表开始增长,上面的代码肯定会让浏览器爬起来……对吧?

4

1 回答 1

0

无需直接在每个img元素上调用请求,您只需将其变为可观察对象并订阅一次,然后将返回的数组显示到您的 html 中。

我使用了几个 RXJS 运算符来得到你想要的。

  • mergeMap扁平化内部的 observable
  • of汽车数组转换为可观察的
  • map汽车数组转换为具有相应汽车图像路径的新数组
  • forkJoin- 我们将多个请求封装到一个 observable 中,并且只有在收到所有请求的响应时才会返回。

这当然只是一种方法,可能还有其他更好的方法。

getCarImages() {
  const cars: Array < {
    carId: number;
  } > = [{
      carId: 1,
    },
    {
      carId: 2,
    },
  ]; 
  of(cars)
  .pipe(
      mergeMap((e) => {
        return forkJoin(
          e.map((item) => this.apiService.getCarImages(item.carId))
        ).pipe(
          map((paths) => {
            console.log(paths);
            return e.map((car, index) => ({
              ...car,
              imagePath: paths[index],
            }));
          })
        );
      })
    )
    .subscribe((res) => {
      this.cars = res;
      console.log(this.cars);
    });
}

HTML:

<div *ngFor="let car of cars">
  <img [src]="car?.imagePath" />
</div>

我创建了一个stackblitz来模拟解决方案。

于 2021-09-22T04:23:43.927 回答