Vuetify でウィンドウの縦幅に合わせてコンテンツサイズを動的に配置・調整する。


# はじめに
Vuetifyはグリッドシステムを備えており、これを活用すればウィンドウの<b>横幅</b>に対してコンテンツが動的に配置・調整されます。

> Grid system
https://vuetifyjs.com/ja/components/grids/

ただ、ウィンドウの<b>縦幅</b>に対する配置・調整が思い通りにならない場面があったため、調査・実施した結果を残します。

### 具体的に説明すること

次のような４つのメニューボタン（アイコンは適当）を表示する画面があったとして
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/376162/dc6cebca-a2b3-b081-85f9-e14aaebc2797.png)

縦幅の大きな余白が気になるので、次のように画面の縦幅が埋まるようにメニューボタンを表示できるようにしたいと思います。
![キャプチャ2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/376162/93d0492a-fb0e-aa4c-88f2-9d07c453b196.png)


※ iPhoneの場合はこうできます。画面サイズが変わっても、実際の画面に応じてメニューボタンのサイズが調整されます。
![キャプチャ5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/376162/08d38955-1a4e-0073-cb0f-256a0aac11d5.png)



# 環境
* Vue.js 2.6.12 
* Vuetify 2.3.10

# 結論

``` Home.vue
<template>
  <div class="Home">
    <v-container fluid >
      <v-row>
        <v-col cols="12">
          <v-row v-resize="onResize" :style="style" >
            <v-col cols="6" v-for="menu in menus" v-bind:key="menu.key">
              <v-btn
                color="accent"
                block
                height='100%'
              >
                <v-icon :size="iconSize">{{menu.icon}}</v-icon>
              </v-btn>
            </v-col>
          </v-row>
        </v-col>
      </v-row>
    </v-container>
  </div>
</template>

<script>

  export default {
    name: 'Home',
    data: () => ({
      menus: [
        { title: 'home', icon: 'mdi-home' },
        { title: 'currency', icon: 'mdi-currency-cny' },
        { title: 'gift', icon: 'mdi-gift' },
        { title: 'kaji', icon: 'mdi-washing-machine'},
      ],
      windowSize: {
        x: 0,
        y: 0,
      },
      iconSize: 0 
    }),

    mounted () {
      this.onResize()
    },

    computed: {
      style () {
        return 'height: ' + this.windowSize.y * 0.8 + 'px;'
      }
    },

    methods: {
      onResize () {
        this.windowSize = { x: window.innerWidth, y: window.innerHeight }
        this.iconSize = window.innerHeight * 0.1
      },
    },
    components: {
    },
  }
</script>
```

# 詳細

基本的な方針としては、windowオブジェクトから取得したウィンドウサイズに応じてコンテンツのstyleを設定します。

また、ウィンドウサイズ変更時に呼び出されるコールバック関数を用意し、ウィンドウサイズに応じてstyleも更新されるようにします。

> Resizing directive
https://vuetifyjs.com/ja/directives/resizing/

このあたりの実装は以下が該当します。
mountedでもonResize()を呼び出すことで初回表示時にwindowSizeに値が格納されるようにします。
computedのstyle()はディレクティブに設定するstyleのとして、windowSizeの値に応じてheightのピクセルを返すようにしています。ウィンドウサイズの0.8倍としているのは決め打ちです。

また、onResize()でアイコンサイズを動的に変更するようにしました。ウィンドウサイズ縦幅の0.1倍としているのは、これまた決め打ちです。

``` vue
<script>
  export default {
    name: 'Home',
    data: () => ({
      windowSize: {
        x: 0,
        y: 0,
      },
    }),

    mounted () {
      this.onResize()
    },

    computed: {
      style () {
        return 'height: ' + this.windowSize.y * 0.8 + 'px;'
      }
    },

    methods: {
      onResize () {
        this.windowSize = { x: window.innerWidth, y: window.innerHeight }
        this.iconSize = window.innerHeight * 0.1
      },
    },
</script>
```

onResize（コールバック関数）とstyleの設定は、コンテンツ（<v-col>）の親要素（<v-row>）で設定します。
ここで必要なのは、<b>`<v-btn>のheight='100%'`</b>を設定しておくことで、ボタンがいい感じにウィンドウサイズ縦幅に合わせて調整されます。

``` vue
．．．
        <v-col cols="12">
          <v-row v-resize="onResize" :style="style" >
            <v-col cols="6" v-for="menu in menus" v-bind:key="menu.key">
              <v-btn
                color="accent"
                block
                height='100%'
              >
                <v-icon :size="iconSize">{{menu.icon}}</v-icon>
              </v-btn>
            </v-col>
          </v-row>
        </v-col>
．．．
```

以上です。