【问题标题】:How to get the data of an img loaded from a src url locally?如何在本地获取从 src url 加载的 img 数据?
【发布时间】:2020-07-15 06:34:24
【问题描述】:

我有一个从后端 API 检索到所有 src 的图像列表:

<div class="repoContent">
    <div *ngFor="let item of repo.value" class="repoItem">
        <img [src]="fetchImage(item.name)" (click)="selectAsset(fetchImage(item.name))" alt="">
    </div>
</div>

用户看到图片后,可以点击图片将一张图片放到 ngx-image-cropper 进行编辑。在这里,我再次使用 url 作为输入。 (可能是 blob base64)

问题是:
每次我单击图像时,都会向我的后端触发另一个 http 请求以获取图像,而我假设这些请求是在本地缓存的。正如我所看到的这些图像,我认为数据存储在客户端计算机上的某个位置,然后我可以在不使用 url 的情况下将 blob 数据传递给 ngx-image-cropper 以避免再次请求后端。我怎么能这样做?


功能更新:

selectAsset(url){
    this.imageSelected=true;
    this.imageFile=null;
    this.imageURL=url;
  }
  fetchImage(name:String):String{
    return GlobalParameterService.apiAssetGet+"?name="+name;
  }

selectAsset 重置裁剪器并放入 url。
fetchImage 构建目标 url

【问题讨论】:

  • 你能显示函数fetchImage()selectAsset()吗?
  • @MichaelD 是的,我添加了它们
  • 不要将 src 绑定到函数,从生命周期挂钩调用函数并将结果分配给组件中的属性。

标签: html angular frontend


【解决方案1】:

您使用函数fetchImage(item.name) 显式地触发了两次请求。将函数绑定到属性通常是一个糟糕的设计。如果您不处理更改检测,这些函数将被多次触发。

您可以做的是在控制器中获取图像并在模板中使用它们。试试下面的

控制器

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

export class AppComponent {
  imageBase64 = '';
  croppedImage: any = '';
  repo = {
    value: [ 
      { name: '100' },
      { name: '200' },
      { name: '400' },
      { name: '500' }
    ]
  };

  constructor() { }

  ngOnInit() {
    const urls = this.repo.value.map(item => this.fetchImage(item.name));
    forkJoin(urls).pipe(
      switchMap(responses => {
        return forkJoin(responses.map(response => this.getBase64(response)));
      })
    ).subscribe(
      (bases: Array<string>) => {
        bases.forEach((base, i) => this.repo.value[i]['base'] = base);
      },
      err => {
        console.log(err);
      }
    );
  }

  fetchImage(name) {
    return from(fetch(`https://picsum.photos/id/${name}/200/200`));
  }

  // Credit: https://stackoverflow.com/a/20285053/6513921
  getBase64(response) {
    return from(response.blob().then(blob => 
      new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onloadend = () => resolve(reader.result);
      reader.onerror = reject;
      reader.readAsDataURL(blob);
    })));
  }

  selectAsset(base: string) {
    this.imageBase64 = base;
  }

  imageCropped(image: any) {
    this.croppedImage = image.base64;
  }

  imageLoaded() {
    // show cropper
  }

  loadImageFailed() {
    // show message
  }
}

模板

<div class="repoContent">
  <div *ngFor="let item of repo.value" class="repoItem">
    <img style="cursor: pointer" [src]="item.base" #img (click)="selectAsset(item.base)" alt="">
  </div>
</div>

<hr>
<image-cropper
    [imageBase64]="imageBase64"
    [resizeToWidth]="0"
    format='png'
    (imageCropped)="imageCropped($event)"
    (imageLoaded)="imageLoaded()"
    (loadImageFailed)="loadImageFailed()"
></image-cropper>

<img [src]="croppedImage" />

这里我使用了repo 变量和https://picsum.photos API 作为示例。用您自己的变量替换它。我还使用 RxJS 的 from 函数将 Promises 转换为 Observables,并使用 forkJoin 函数组合多个 observables。

工作示例:Stackblitz

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-17
    相关资源
    最近更新 更多