riefuchi220 / poke

0 stars 0 forks source link

Imgタグ #34

Open riefuchi220 opened 4 months ago

riefuchi220 commented 4 months ago

<v-img>コンポーネントを<img>タグに置き換える場合のデメリットや考慮点は以下の通りです。

<v-img>のメリットとその代替手段

<v-img>コンポーネントには、画像表示を簡単にするための多くの機能が備わっています。以下はその主要な機能と、<img>タグに置き換えた場合の代替手段です。

  1. プレースホルダー:

    • <v-img>コンポーネントはv-slot:placeholderスロットを使用して、画像がロードされるまでの間にプレースホルダーを表示できます。
    • 代替手段: 前述のように、<img>タグを使用する場合は、プレースホルダーを手動で管理します。
  2. オブジェクトフィット(object-fit):

    • <v-img>containcoverなどのプロパティを持ち、画像の表示方法を簡単に制御できます。
    • 代替手段: CSSのobject-fitプロパティを使用して、同様の効果を得ます。

      .img-responsive {
      width: 100%;
      height: auto;
      display: block;
      object-fit: cover; /* または contain */
      }
  3. カスタムCSSクラス:

    • <v-img>classプロパティをサポートしており、簡単にカスタムスタイルを適用できます。
    • 代替手段: <img>タグでも同様にclass属性を使用してカスタムスタイルを適用できます。
  4. eager プロパティ:

    • <v-img>eagerプロパティを使うと、画像の遅延読み込み(lazy loading)を制御できます。
    • 代替手段: <img>タグの場合、loading属性を使用して遅延読み込みを制御できます。

      <img src="image.jpg" loading="eager" alt="Image">
  5. エラー処理:

    • <v-img>@errorイベントを提供し、画像読み込みエラー時の処理を簡単に追加できます。
    • 代替手段: <img>タグでもonerror属性を使用してエラー処理を追加できます。

      <img src="image.jpg" @error="handleImageError" alt="Image">

<img>タグでの実装

以下は、<v-img>の機能を代替するために<img>タグを使用した完全な例です。

<template>
  <div>
    <div v-if="imageLoading" class="placeholder">
      <!-- プレースホルダーコンテンツ -->
      <span>Loading...</span>
    </div>
    <img
      v-else
      :src="sliderImages[localCurrentIndex]"
      @load="handleImageLoad"
      @error="handleImageError"
      :class="{'img-loaded': !imageLoading, 'img-responsive': true}"
      alt="Image"
    />

    <!-- 再生ボタン -->
    <button v-show="status === 'none' || status === 'stop'" @click="startPlayback">
      再生
    </button>
    <!-- 停止ボタン -->
    <button v-show="status === 'play'" @click="stopPlayback">
      停止
    </button>
    <!-- 準備中アイコン -->
    <span v-show="status === 'ready'">
      準備中...
    </span>

    <!-- スライダーバー -->
    <input type="range" :disabled="status === 'none'" v-model="localCurrentIndex" />
  </div>
</template>

<script>
export default {
  props: {
    isModal: {
      type: Boolean,
      default: false
    },
    imageUrls: {
      type: Array,
      required: true
    }
  },
  data() {
    return {
      imagesLoaded: false,
      imageLoading: true,
      sliderImages: [], // プリロードされた画像のURL
      localCurrentIndex: 0
    };
  },
  computed: {
    status: {
      get() {
        return this.isModal ? this.$store.state.modalSlider.status : this.$store.state.normalSlider.status;
      },
      set(status) {
        const mutation = this.isModal ? 'updateModalSliderStatus' : 'updateNormalSliderStatus';
        this.$store.commit(mutation, status);
      }
    }
  },
  methods: {
    startPlayback() {
      this.status = 'play';
    },
    stopPlayback() {
      this.status = 'stop';
    },
    preloadImages(imageUrls) {
      return Promise.all(
        imageUrls.map((url) => {
          return new Promise((resolve, reject) => {
            const img = new Image();
            img.src = url;
            img.onload = () => resolve(url); // URLを解決
            img.onerror = reject;
          });
        })
      );
    },
    handleImageLoad() {
      this.imageLoading = false;
    },
    handleImageError() {
      console.error('画像のロードに失敗しました');
    }
  },
  mounted() {
    this.preloadImages(this.imageUrls)
      .then((loadedImages) => {
        this.sliderImages = loadedImages; // プリロードされた画像のURLを設定
        this.imagesLoaded = true;
        this.status = 'none'; // プリロード完了後、スライダーを初期状態に設定
        this.imageLoading = false; // 画像ロード完了後、プレースホルダーを非表示にする
      })
      .catch((err) => {
        console.error('画像のプリロード中にエラーが発生しました', err);
      });
  },
  watch: {
    localCurrentIndex() {
      this.imageLoading = true; // 画像のインデックスが変更されたときにプレースホルダーを表示
    },
    status(newVal) {
      if (newVal === 'play') {
        // 再生を開始する処理
      } else if (newVal === 'stop') {
        // 再生を停止する処理
      } else if (newVal === 'ready') {
        // 画像を取得中の処理
      } else if (newVal === 'none') {
        // 初期状態の処理
      }
    }
  }
};
</script>

<style scoped>
.placeholder {
  width: 100%;
  height: auto;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #f0f0f0; /* プレースホルダーの背景色 */
}

.img-responsive {
  width: 100%;
  height: auto;
  display: block;
  object-fit: cover; /* 必要に応じて contain に変更 */
}

.img-loaded {
  display: block;
}
</style>

まとめ

<v-img>の機能を<img>タグに置き換えることで実現する場合、スタイルやプレースホルダーなどの機能を手動で管理する必要があります。しかし、チラつきの問題を解消するためにはこのアプローチが有効である可能性が高いです。必要な機能に応じて、<v-img>コンポーネントの代替手段を適切に実装してください。