画像と短い説明を含むカードの長いリストがあるアプリ (Ionic 5 + Angular 9 + Capacitor) を作成しています。したがって、この場合、長いリストを含むページの読み込みが遅すぎるため、仮想スクロールを使用する必要があります。問題は、上下にスクロールするたびに同じ画像 (外部 URL から) が再度ロードされることです。モバイル接続 (3G など) を使用している場合は非常に悪いです。また、オフラインの場合はこれらの画像を使用したいと思います。 /接続を緩めます。
なんとか解決しましたが、上下にスクロールする速度が速すぎると、正しい画像が間違った画像に置き換えられます。仮想スクロールのせいだと思います。
それで、仮想スクロールを使用する場合、画像のキャッシュとオフラインでの使用に使用できる良い解決策を知っていますか?
まず ServiceWorker を使いたかったのですが、デバイス上でアプリをビルドするとうまくいきません。この問題の詳細については、https ://github.com/ionic-team/ionic/issues/20890 を参照してください。
このプラグインhttps://github.com/zyra/ionic-image-loaderも見つけましたが、Ionic 5 と Capacitor では機能しません。
だから、今のところ私の解決策は次のようなものです:
home.page.html:
<ion-virtual-scroll class="scroll" [items]="_filteredEvents" approxItemHeight="126px">
<app-event-list-card *virtualItem="let event" [event]="event" [networkStatus]="_networkStatus" style="opacity:1"></app-event-list-card>
</ion-virtual-scroll>
イベントリストカード.component.ts:
ngOnChanges(changes: SimpleChanges) {
Storage.get({key: 'img' + this.event.id}).then((image) => {
if (image.value) {
this.event.image = image.value; // todo: do not assign a variable to event object
this.changeDetectorRef.markForCheck();
} else if(this.networkStatus) {
this.convertImageToBase64(this.event.image).then((dataUrl: string) => {
Storage.set({key: 'img' + this.event.id, value: dataUrl});
});
this.changeDetectorRef.markForCheck();
} else {
this.event.image = this.transparentImage;
}
});
}
private async convertImageToBase64(url): Promise<any> {
const response = await fetch(url);
const blob = await response.blob();
const result = new Promise((resolve, reject) => {
if (blob.type === 'text/html') {
resolve(this.transparentImage);
} else {
const reader = new FileReader();
reader.onloadend = () => resolve(reader.result);
reader.onerror = () => reject;
reader.readAsDataURL(blob);
}
});
return await result;
}
イベント リスト カード コンポーネント.html:
<ion-card *ngIf="event" [routerLink]="'/event-details/' + event.id" [class]="event.cancelled == 1 ? 'event-card__card event-card__card--cancelled' : 'event-card__card'">
<ion-card-content class="event-card__inner">
<ion-grid class="ion-no-padding">
<ion-row class="ion-align-items-center">
<ion-col size="5">
<ion-thumbnail class="event-card__thumb">
<!--<ion-img [src]="event.image" (ionError)="loadDefaultImage($event)" alt="Image - {{ event.name}}"></ion-img>-->
<img [src]="sanitizer.bypassSecurityTrustResourceUrl(event.image)" onerror="this.src='data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'" crossorigin="anonymous">
</ion-thumbnail>
</ion-col>
<ion-col size="7" class="event-card__description ion-no-padding">
<ion-row class="ion-text-center">
<h2 class="event-card__title">{{ (event.name) }}</h2>
</ion-row>
<ion-row class="ion-text-center">
<h4 class="event-card__category">{{ event.event_type }}</h4>
</ion-row>
<ion-row class="ion-text-center">
<h3 class="event-card__location">{{ event.location }}</h3>
</ion-row>
</ion-col>
</ion-row>
</ion-grid>
</ion-card-content>
</ion-card>
ここで onChanges を使用しているのは、仮想スクロールで onInit を使用すると、アイテムが 100 個あっても約 10 回しか実行されないためです。仮想スクロールは、新しいカードを作成するのではなく、カードを置き換えます。