Vue3とVuetifyでゲームみたいなメニューを作る

今日は前回紹介したVueのUIライブラリのVuetifyを使ってゲームのスタート画面のようなUIを作ってみます。

今日のテーマは、Vueの基礎、JavaScriptの基礎、CSSの基礎の復習や知識を固めるために練習する良い素材になると思います。

完成したコードはGitHubで公開しているので見てみてください。

前回の続きなのでVue+Vuetifyのプロジェクトを用意して早速とりかかりましょう。

もし、Vuetifyを使いたくない方はViteでVueのプロジェクトを作成するだけでも同じことができるのでご安心を。

まずは、使えそうなレイアウトをコピペします。

<template>
  <v-container class="bg-surface-variant mb-6">
    <v-row align="center" no-gutters style="height: 150px">
      <v-col v-for="n in 3" :key="n">
        <v-sheet class="pa-2 ma-2"> .align-center </v-sheet>
      </v-col>
    </v-row>
  </v-container>
</template>

v-containerは、コンテンツを左右の真ん中と、上下の真ん中に位置させることができるコンポーネントです。

v-rowは、v-colのwrapper(囲うもの)でflexを使って中のcol(カラム)のレイアウトをコントロールすることができます。

v-colはかならずv-rowの直下に位置されます。ここに表示されるコンテンツを入れることになります。

v-sheetは複数のコンポーネントで使えるベースラインになります。

レイアウトの作成

では、ゲームの画面のように左側にメニュー、右側にカードを作成します。

<script setup></script>

<template>
  <v-container class="main-container">
    <v-row class="nav-row">
      <div class="left-col">
        <v-sheet class="my-4">Menu</v-sheet>
        <v-sheet class="my-4">Menu</v-sheet>
        <v-sheet class="my-4">Menu</v-sheet>
        <v-sheet class="my-4">Menu</v-sheet>
      </div>
      <div class="center-col"></div>
      <div class="right-col">
        <v-sheet class=""> .v-col- </v-sheet>
      </div>
    </v-row>
  </v-container>
</template>

<style>
.main-container {
  min-width: 100vw;
  min-height: 100vh;
  width: 100vw;
  height: 100vh;
  background-color: black;
  display: flex;
  align-items: center;
  justify-content: center;

}

.nav-row {
  display: flex;
  justify-content: center;
  margin: 1em;
  height: 90vh;
  background-color: rgb(160, 35, 104);
}

.left-col {
  width: 30vw;
  display: flex;
  flex-direction: column;
  justify-content: center;
  margin: 1em;
  background-color: blue;
}

.center-col {
  width: 10vw;
}

.right-col {
  width: 50vw;

  margin: 1em;
  background-color: blue;
}
</style>

Vueitfyのv-colにはmax-widthが100%で設定されていたため、divに右と左のcolクラスを作成して別々のサイズにしました。

見やすいようにわざと色を付けていますが、後から外します。

背景画像

では、バックグラウンドの画像をPixabayで見つけて貼り付けます。これは商用無料で使える写真を探すときに便利なサイトです。

背景画像のファイルはsrc/assetsに、bg-img.jpgファイルで置いておきます。プロジェクトが大きくなったら、画像をまとめる用のフォルダを作成するべきですが今はOKとします。

ではスタイルに追加します。

.main-container {
  min-width: 100vw;
  min-height: 100vh;
  width: 100vw;
  height: 100vh;
  background-image: url(./assets/bg-img.jpg);
  background-size: cover;
  display: flex;
  align-items: center;
  justify-content: center;

}

このように背景画像が加わり、いい感じになりました。

メニューの作成

メニュー(ナビゲーションバー)を作成します。これは別のコンポーネントを作成してApp.vueにインポートする形にします。

では、components/Menu.vueファイルを作成して下記のように書きます。

<template>
  <v-hover>
    <template v-slot:default="{ isHovering, props }">
      <v-card
        v-bind="props"
        :color="isHovering ? 'primary' : undefined"
        title="Hover over me"
        text="..."
        class="my-4"
      ></v-card>
    </template>
  </v-hover>
</template>

次にApp.vueの方でこのコンポーネントをインポートしてあげます。

<script setup>
import Menu from './components/Menu.vue'
</script>

<template>
  <v-container class="main-container">
    <v-row class="nav-row">
      <div class="left-col">
        <Menu/>
        <Menu/>
        <Menu/>
        <Menu/>
      </div>
      <div class="center-col"></div>
      <div class="right-col">
        <v-sheet class=""> .v-col- </v-sheet>
      </div>
    </v-row>
  </v-container>
</template>

これでホバーエフェクトのあるメニューができました。次にメニューのタイトルをpropsとして親コンポーネントのApp.vueから子のMenu.vueに渡してあげます。

次に、メニューにガラスのような透明エフェクトをかけたいのでこのCSSツールから作成します。他にもデザインで使えるCSSツールを記事にしているので是非読んでください。

とりあえず、このような感じになりました。

コードはこのようになります。

Menu.vue

<script setup>
import { defineProps } from "vue";

const menuProps = defineProps({
  title: String,
});
</script>

<template>
  <v-hover>
    <template v-slot:default="{ isHovering, props }">
      <v-card
        v-bind="props"
        :color="isHovering ? 'primary' : undefined"
        :title="menuProps.title"
        class="my-4 ma-4 glass"
      ></v-card>
    </template>
  </v-hover>
</template>

<style scoped>
.glass {
  background: rgba(48, 29, 183, 0.4);
  box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37);
  backdrop-filter: blur(7px);
  -webkit-backdrop-filter: blur(7px);
  border-radius: 10px;
  border: 1px solid rgba(255, 255, 255, 0.18);

  color: white;
}
</style>

コンテンツを作成

次に、各メニューをクリックした際に表示される右側のコンテンツのコンポーネントを作成します。ファイルはcomponents/Content.vueの名前にしました。これも同じようにApp.vueにインポートさせます。

コンテンツの中身もpropsでContent.vueに渡してあげるようにします。

      <div class="right-col">
        <Content content="ホーム" v-show="isOpen1" />
        <Content content="マップ" v-show="isOpen2" />
        <Content content="コントロール" v-show="isOpen3" />
        <Content content="コンタクト" v-show="isOpen4" />
      </div>

次に、メニューボタンをクリックしたときに各コンテンツが切り替わるようにします。

App.vue

<script setup>
import { ref } from "vue";
import Menu from "./components/Menu.vue";
import Content from "./components/Content.vue";

const isOpen1 = ref(true);
const isOpen2 = ref(false);
const isOpen3 = ref(false);
const isOpen4 = ref(false);

function openContent(num) {
  closeAll();
  switch (num) {
    case 1:
      isOpen1.value = true;
      break;
    case 2:
      isOpen2.value = true;
      break;
    case 3:
      isOpen3.value = true;
      break;
    case 4:
      isOpen4.value = true;
      break;
  }
}

function closeAll() {
  isOpen1.value = false;
  isOpen2.value = false;
  isOpen3.value = false;
  isOpen4.value = false;
}
</script>

<template>
  <v-container class="main-container">
    <v-row class="nav-row">
      <div class="left-col">
        <Menu title="Home" @click="openContent(1)" />
        <Menu title="Map" @click="openContent(2)" />
        <Menu title="Control" @click="openContent(3)" />
        <Menu title="Contact" @click="openContent(4)" />
      </div>
      <div class="center-col"></div>
      <div class="right-col">
        <Content content="ホーム" v-show="isOpen1" />
        <Content content="マップ" v-show="isOpen2" />
        <Content content="コントロール" v-show="isOpen3" />
        <Content content="コンタクト" v-show="isOpen4" />
      </div>
    </v-row>
  </v-container>
</template>

Content.vueはとりあえずこのようにしておきます。

親のApp.vueからコンテンツのpropsをもらえるようにしておきます。

Content.vue

<script setup>
import { defineProps } from "vue";

const props = defineProps({
  content: String,
});
</script>

<template>
  <div class="content-wrapper glass">
    {{ props.content }}
  </div>
</template>

<style scoped>
.glass {
  background: rgba(48, 29, 183, 0.4);
  box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37);
  backdrop-filter: blur(7px);
  -webkit-backdrop-filter: blur(7px);
  border-radius: 10px;
  border: 1px solid rgba(255, 255, 255, 0.18);
}

.content-wrapper {
  width: 100%;
  height: 100%;
  color: white;
}
</style>

これでクリックするとコンテンツが表示されるようにはなりました。

次にransform: perspective(600px) rotateY(10deg);のCSSを左と右のcolクラスに追加して、3Dに見えるようにします。

最後にボタンがアクティブの際にボタンに色を付けて完了です。

完成したイメージはこちらです。

完成したコードはこちら(GitHub)からどうぞ。

2 thoughts on “Vue3とVuetifyでゲームみたいなメニューを作る”

  1. お疲れ様です!
    凄いかっこいいですね。
    プロジェクト進める上で参考になります。
    ゲーム以外でも使えそうですね

    • _kyouさん、お疲れ様です。CSSだけでも3Dのスタイルができるので是非試してみてください!
      VuetifyはUIコンポーネントは良いと思いましたが、レイアウトを設定するには普通のCSSの方が良いという印象を受けました。
      コメントありがとうございます。

Comments are closed.