【 Vue3 】表示させた画像の高さと数を取得してCSSを可変させる

## 概要
この記事では、Vueで表示させた画像の高さと表示数からCSSを可変させる方法をご紹介します。

## どんな時に使うのか
例えば、ユーザーもしくは管理者が登録した複数の画像を同時に表示させる際、表示させた画像の高さや数に合わせてCSSの値を変化させたい時など。

## 実装

### 親コンポーネント
`ImageDisplay`コンポーネントで
```vuejs
<template>
<div class="mait-layout" :style="rootStyle">
　　　　　　<div ref="componentRef" class="fixed-banner">
     <!-- ImageDisplayコンポーネントがロードされたタイミングでimageLoad関数を実行 -->
     <ImageDisplay :images="images" @load="loadImage" />
   </div>
</div>
</template>
<script lang="ts">
import {
  ref,
} from '@nuxtjs/composition-api';
export default defineComponent({
  components: {
    ImageDisplay,
  },
  setup() {
    const images = ref<ImageIndex[]>([]); // ①api.ts内のinterface ImageIndexで型定義してある
    const componentRef = ref<HTMLElement>(); // ②HTMLElement型の変数
    const bannerHeight = ref(0); // ③取得した画像の高さを入れるためのリアクティブな変数

    const loadImage = () => {
      if(!componentRef.value) return;
      imageHeight.value = componentRef.value.clientHeight; // ④画像の高さを取得
    };

    const rootStyle = computed(() => {
      return {
        'padding-bottom': imageHeight.value + 'px',
      };
    });

    return { loadImage, imageHeight, rootStyle };
  },
});
</script>
```

①：images変数に画像を表示させるために必要なデータが格納される。
　　api.ts内のinterface `ImageIndex`でサーバーから受け取るデータの型定義がしてある。
②：HTMLElement型のリアクティブな変数を定義。HTMLElement型にすることで、`<div>`、`<p>`、`<image>`タグなどのDOM要素を参照することができるようになる。
③：取得した画像の高さを入れるためのリアクティブな変数。
④：HTMLElement型変数のvalueから画像の高さを取得できる。

### 補足
今回classに適用してるcssに関してはあまり触れてません。
適用してるcssは以下のような感じ。
簡単に説明すると、main-layoutクラス直下のfixed-imageクラスに対して、main-layoutクラス要素の一番下にfixed-imageクラスの要素を固定配置させてるイメージです。
（固定配置させてるので、ブラウザをスクロールしても配置した画像は固定されたままになります。）

```
.main-layout {
  // 省略
  > .fixed-image {
      position: fixed;
      bottom: 0;
      width: 100vw;
  }
}
```

### 子コンポーネント

```vuejs
<template>
  <div>
    <div v-for="item in images" :key="item.id" class="parent-container">
      <img
        :src="getImageSrc(item)"
        :style="imageHeight"
        @load="loadImage"
      />
    </div>
  </div>
</template>
<script lang="ts">
import { computed, defineComponent } from '@nuxtjs/composition-api';

export default defineComponent({
  name: 'ImageDisplay',
  props: {
    images: {
      type: Array,
      required: true,
    },
  },
  setup(_, { emit }) {
    // 今回は省略（画像表示のための処理をここでしています）
    const getImageSrc = () => {};

　　　　　　　　// ①親イベントに向けてloadという名前のカスタムイベントを発火
    const loadImage = (event: Event) => {
      emit('load');
    };

    // computed()を使うことで、内部で使用しているデータの変化を自動的に追跡することができる
　　　　　　　　// ここで自動的に算出したcssプロパティをimgタグのstyleに当てている
    const imageHeight = computed(() => {
      return {
        width: '100%',
　　　　　　　　　　　　　　　　// ②「window.innerWidth」は、ブラウザウィンドウの内部の幅を表してる
        height: (window.innerWidth * 100) / 320 + 'px',
      };
    });

    return {
      getImageSrc,
      loadImage,
      bannerHeight,
    };
  },
});
</script>
```

①：親イベントに向けてloadという名前のカスタムイベントを発火
②：`window.innerWidth`はブラウザウィンドウの内部の幅を表してる
`height: (window.innerWidth * 100) / 320 + 'px'`とすることで、ウィンドウの幅を`320`という基準値と比較し、適切な高さを算出。`100`をかけることでウィンドウの幅と画像表示の高さとの比率を調整している。

## まとめ
ざっくりとした説明になりますが、上記のような感じにすることで表示させた画像の高さを取得してCSSを可変させることができます。
画像を特定の位置に固定させるときは必要ありませんが、動的に表示させたい時などに役立つので是非参考にしてみてください！
間違ってる箇所等あればコメントお願いいたします🙇