Ioni c 5: VirtualScroll и кэширование изображений - PullRequest
0 голосов
/ 04 апреля 2020

Я создаю приложение (Ioni c 5 + Angular 9 + Capacitor), в котором у меня есть длинные списки карточек, содержащие изображения и краткое описание. Итак, в этом случае я должен использовать виртуальную прокрутку, потому что в противном случае страницы с длинными списками загружаются слишком медленно. Проблема в том, что одни и те же изображения (из внешнего URL-адреса) загружаются снова каждый раз при прокрутке вниз и вверх, поэтому очень плохо, если вы используете мобильное соединение (3G et c.), А также я хотел бы использовать эти изображения, если Вы отключены / потеряете соединение.

Однако я могу решить это каким-то образом, если вы слишком быстро прокрутите вниз и вверх, правильные изображения будут заменены неправильными. Думаю, это из-за виртуальной прокрутки.

Итак, знаете ли вы какое-нибудь хорошее решение, которое я мог бы использовать для кэширования изображений и их автономного использования, если я использую виртуальную прокрутку?

Во-первых, я хотел использовать ServiceWorker, но он не работает, если вы создаете приложение на устройстве. Подробнее об этой проблеме читайте здесь: https://github.com/ionic-team/ionic/issues/20890

Я также нашел этот плагин https://github.com/zyra/ionic-image-loader, но он не работает с Ioni c 5 и конденсатором .

Итак, мое решение на данный момент выглядит примерно так:

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>

event-list-card.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;
  }

event-list-card-component. 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 с виртуальной прокруткой, он будет выполняться только при 10 раз, даже если у вас есть 100 предметов - виртуальные свитки заменяют карты вместо создания новых.

...