web-dev-qa-db-ja.com

Ionic 2または3アプリで実際の画像が読み込まれる前にプレースホルダー画像を表示する方法

良い一日、

私はIonicアプリケーションで作業しており、JSONフィードから動的に画像をロードしています。画像が外部URLからプルされているときに、プレースホルダー画像が表示されるようにしたいのですがその場所、その後、プレースホルダー画像は、読み込まれると「実際の」画像に置き換えられます。

私の現在の状況の例は:

<ion-card *ngFor="let item of items"...
 <img [src]="item.picture" />

ありがとうございます。それでは、お元気で。

12
TC Roberts

JSONを変更してloaded booleanプロパティを持つことができますか?これが簡単な場合は、次のようにします。

_<ion-card *ngFor="let item of items">
  <img [src]="item.picture" (load)="item.loaded = true" [hidden]="!item.loaded" />
  <img src="../path/to/your/placeholer/image.jpg" [hidden]="item.loaded">
</ion-card>
_

ロードされたプロパティは常にfalseとして初期化されます。画像が読み込まれると、_(load)_イベントが発生し、画像の読み込まれたプロパティがtrueに変更され、プレースホルダー画像が非表示になり、読み込まれた画像が表示されます。

このJSONを変更できない場合(またはサイズが大きすぎて編集できない場合)、上記のコードを使用できますが、ページで次のようにしてください_.ts_

_public functionWhoseIsLoadingYourJson(){
  // HTTP REQUEST FOR JSON
  .subscribe(response => {
    response.forEach(element => {
      element.loaded = false;
    });
    this.items = response;
  });
}
_

応答を繰り返し、すべてのオブジェクトでロードされたプロパティをfalseに設定します。これが何らかのエラーをスローする場合、* ngIfを使用して_<ion-card>_をdiv内に置くことができます

_<div *ngIf="this.items != null">
  <!-- ion card -->
</div>
_

編集-JSONの更新

Firebaseから提供されているため、JSONを更新するには3つのオプションがあります。 1つ目は、データベースを更新するために1回だけ実行する関数です。2つ目は、私が与えたコードです(結果を繰り返し処理し、ブール値をプッシュします)が、Firebaseを使用しているため、異なります。

最初の解決策:

あなたのコードのどこかで、それはどんなページでもかまいません、あなたはそれを一度実行するだけです:

_firebase.database().ref('myDataNode').on('value', snapshot => {
  for(let key in snapshot.val()){
    firebase.database().ref('myDataNode/' + key + '/loaded').set(false);
  }
});
_

myDataNodeのすべての結果をループし、それらのキーを使用してloadedプロパティをfalseに設定していることを確認してください。ただし、setを使用する場合は注意してください。すべてのノードをオーバーライドできるため、この方法を実行する前に、Firebaseノードをエクスポートしてバックアップを作成することを忘れないでください。また、コード内の任意の場所から画像をFirebaseにプッシュする場合は、loadedプロパティを一緒に設定するように変更することを忘れないでください。

前述のように、2つ目はこの回答で行ったものですが、Firebase呼び出し内で使用し、スナップショットに付属するforEachメソッドを使用します。

_firebase.database().ref('myDataNode').on('value', snapshot => {
  snapshot.forEach(element =>{
    this.myDataNode.Push({
      picture: element.val(), // maybe it needs to be element.val().nameOfYourProperty
      loaded: false
    })
  });
});
_

これにより、画像のURLと読み込まれたプロパティを持つ新しい要素が配列にプッシュされます。 .Push()メソッドを認識できない場合は、配列として型指定された変数を宣言します。

_public myDataNode: any[];
_

3つ目は、ローカルでの更新、firebaseスナップショットの反復、ローカル変数への結果の保存、新しいプロパティの作成、配列へのプッシュです。

_firebase.database().ref('myDataNode').on('value', snapshot => {
  for (let key in snapshot.val()){
    snapshot.forEach(item => { // iterate snapshot
      let record = item.val(); // save the snapshot item value in a local variable
      record.loaded = true; // add the property
      this.newArray.Push(record); // Push it to your array that'll  be used in ng-for
      return true; // return true to foreach
    });
  }
});
_

お役に立てれば。

1
Gabriel Barreto

ほとんどの回答は、同じビューにloaded checkのロジックを追加することに関するものですが、適切ではないようです。代わりに、それを処理する独自のディレクティブを作成できます。 この驚くべき記事を見て、それがどのように実行できるかを確認できます。

最初のコピーこのGIFsrc/assetsフォルダに名前を付け、preloader.gif

次に、このカスタムディレクティブを追加します。コードはほとんど自明です:

// An image directive based on http://blog.teamtreehouse.com/learn-asynchronous-image-loading-javascript
import {Directive, Input, OnInit} from '@angular/core';

// Define the Directive meta data
@Directive({
  selector: '[img-preloader]', //E.g <img mg-img-preloader="http://some_remote_image_url"
  Host: {
    '[attr.src]': 'finalImage'    //the attribute of the Host element we want to update. in this case, <img 'src' />
  }
})

//Class must implement OnInit for @Input()
export class ImagePreloader implements OnInit {
  @Input('img-preloader') targetSource: string;

  downloadingImage : any; // In class holder of remote image
  finalImage: any; //property bound to our Host attribute.

  // Set an input so the directive can set a default image.
  @Input() defaultImage : string = 'assets/preloader.gif';

  //ngOnInit is needed to access the @inputs() variables. these aren't available on constructor()
  ngOnInit() {
    //First set the final image to some default image while we prepare our preloader:
    this.finalImage = this.defaultImage;

    this.downloadingImage = new Image();  // create image object
    this.downloadingImage.onload = () => { //Once image is completed, console.log confirmation and switch our Host attribute
      console.log('image downloaded');
      this.finalImage = this.targetSource;  //do the switch ????
    }
    // Assign the src to that of some_remote_image_url. Since its an Image Object the
    // on assignment from this.targetSource download would start immediately in the background
    // and trigger the onload()
    this.downloadingImage.src = this.targetSource;
  }

}

次に、次のように新しいディレクティブをアプリモジュールに追加します。

import { NgModule, ErrorHandler } from '@angular/core';
import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
import { MyApp } from './app.component';
import { ImagePreloader } from '../components/img-preload/img-preload';

@NgModule({
  declarations: [
    MyApp,
    ImagePreloader, // <------- Here!
    // ...
  ],
  imports: [
    IonicModule.forRoot(MyApp)
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    // ...
  ],
  providers: [{provide: ErrorHandler, useClass: IonicErrorHandler}]
})
export class AppModule {}

これは、新しいカスタムディレクティブを使用する方法です。

<img img-preloader="https://images.unsplash.com/photo-1413781892741-08a142b23dfe" alt="">

これは次のようになります。

Result

次に、画像のコンテナの高さ/幅を設定して、プリローダーgifと最終画像の両方が同じサイズになるようにします。

20
sebaferreras

以下のようにしてみてください。プレースホルダー画像はassets/imagesフォルダーに保存できます。

。html

<ion-card *ngFor="let item of items">
 <img [src]="item?.picture!= null ? item.picture : myImgUrl" />
</ion-card>

。ts

export class MyPage{
   myImgUrl:stirng='./assets/images/myimage.png;

   constructor(){}
}
0
Sampath

私の知る限り、Ionicを実行する方法はありません。ただし、javascriptとcssを使用して実行できます。

CSSの方法:

画像をカバーするdivを作成し、プレースホルダー画像をそのdivのbackground-imageに設定します。

<div class="image">
    <img src="your_main_image"/>
</div>
.image{
    background-image: url('your_placeholder_image');
}

JavaScriptの方法:

Stackoverflowで簡単に見つけることができるJavaScriptによる方法がいくつかあるので、ここでは再回答しません。 これ は例です

0
Duannx