Nuxt.jsでVuetifyを使う(with vue-property-decorator)

2020.09.20

スクラッチでNuxt.jsをTypeScriptを利用して開発する環境に対して、Vuetifyを使う環境作成の手順を確認したかったので、方法を調べつつ実際に作成してみました。

前回作成した記事(「Nuxt.jsでTypeScriptを使う(with vue-property-decorator)」)で作成した環境に対して、Vuetifyを使う環境にするための方法についてまとめています。

前回と同様に、できる限りミニマムな構成で作成したいのと、自分的には理解のブラックボックス化が進みやすいため可能な限りVue CLIやcreate-nuxt-appは使用したくなかったため使用していません。(より簡単に早く、動くものを作りたい場合にはVue CLIやcreate-nuxt-appの利用をおすすめします。)

はじめに

やってみたこと

@nuxtjs/vuetifyの導入

$ npm i --save-dev @nuxtjs/vuetify

nuxt.config.jsの修正

nuxt.config.js

export default {
  buildModules: ['@nuxt/typescript-build','@nuxtjs/vuetify']
}

動作確認

  • Vuetifyの以下のページに基本的なレイアウトのサンプルがありますので、こちらを利用します。
  • 「Baseline」という名称のサンプルを利用します
$ vim pages/vuetify-test.vue
$ npm run dev

pages/vuetify-test.vue

<!-- (こちらに「Baseline」のコードを転記) -->
  • 次のように表示されることを確認します。

アレンジ1:TypeScript&クラススタイル化

引用したサンプルは、Vuetifyの基本的なレイアウト方法に則っている上に、いくつかのイケてるインタラクションも実装されていて、初めて触るのにちょうどいい感じのボリュームではある・・・のですが、不慣れな僕にとってはちょっと長くて理解に時間がかかったので、よりスリムな内容に書き換えてみました。

その上で、TypeScript&クラススタイルに変更しました。

やったこと

$ vim pages/vuetify-test.vue
$ npm run dev

pages/vuetify-test.vue

<template>
  <v-app id="inspire">
    <v-navigation-drawer
      v-model="drawer"
      app
    >
      <v-list>
        <v-list-item link>
          <v-list-item-action>
            <v-icon>mdi-home</v-icon>
          </v-list-item-action>
          <v-list-item-content>
            <v-list-item-title>Home</v-list-item-title>
          </v-list-item-content>
        </v-list-item>
      </v-list>
    </v-navigation-drawer>

    <v-app-bar app>
      <v-app-bar-nav-icon @click.stop="drawer = !drawer"></v-app-bar-nav-icon>
      <v-toolbar-title>Application</v-toolbar-title>
    </v-app-bar>

    <v-main>
      <v-container class="fill-height">
        <v-row>
          <v-col class="text-center">
            <v-btn><v-icon large>mdi-code-tags</v-icon></v-btn>
          </v-col>
        </v-row>
      </v-container>
    </v-main>
    <v-footer app>
      <span>&copy; {{ new Date().getFullYear() }}</span>
    </v-footer>
  </v-app>
</template>

<script lang="ts">
import { Component, Vue } from "vue-property-decorator";

@Component({
  components: {
  },
})
export default class VuetifyTestPage extends Vue {
  drawer = null
}
</script>

次のように表示されることを確認します。

やったことの解説 - 変更点

  • 左メニューの項目を一つだけに減らす
  • v-app-barのオプションはVuetify的なレイアウト上必須なもの( app )だけにする
  • メインコンテンツエリアのボタン( v-btn )の装飾やインタラクションを最小限にする
  • footerの class="white--text を外す
  • scriptタグの内容を vue-property-decorator を使う形式で書き直す

やったことの解説 - ポイント

  • v-app以下にコンポーネントを配置
  • 4つの領域に分ける
    • v-navigation-drawer:左メニュー
    • v-app-bar:ヘッダー
    • v-main:メインコンテンツ
    • v-footer:フッター
  • メインコンテンツ配下は上下中央に配置される( class="fill-height" 指定により)

アレンジ2:layout化

各pageの内容がメインコンテンツ内に入るような構成にするために、前セクションでアレンジしたものをデフォルト適用されるlayout化します。

$ mkdir layouts
$ mv pages/vuetify-test.vue layouts/default.vue

layouts/default.vue

<template>
  <v-app id="inspire">
    <v-navigation-drawer
      v-model="drawer"
      app
    >
      <v-list>
        <v-list-item link>
          <v-list-item-action>
            <v-icon>mdi-home</v-icon>
          </v-list-item-action>
          <v-list-item-content>
            <v-list-item-title>Home</v-list-item-title>
          </v-list-item-content>
        </v-list-item>
      </v-list>
    </v-navigation-drawer>

    <v-app-bar app>
      <v-app-bar-nav-icon @click.stop="drawer = !drawer"></v-app-bar-nav-icon>
      <v-toolbar-title>Application</v-toolbar-title>
    </v-app-bar>

    <v-main>
      <v-container class="fill-height">
        <nuxt />
      </v-container>
    </v-main>
    <v-footer app>
      <span>&copy; {{ new Date().getFullYear() }}</span>
    </v-footer>
  </v-app>
</template>

<script lang="ts">
import { Component, Vue } from "vue-property-decorator";

@Component({
  components: {
  },
})
export default class VuetifyTestPage extends Vue {
  drawer = null
}
</script>

pages/index.vue

<template>
<div>
  <h1>This is Test</h1>
  <pre>{{testUser}}</pre>
  <v-btn>ボタン</v-btn>
</div>
</template>

<script lang="ts">
import { Component, Vue } from "vue-property-decorator";

@Component({
  components: {
  },
})
export default class IndexPage extends Vue {
  myname = {
      firstName: "aki",
      lastName: "kato"
    }
  get testUser(){
    return this.myname
  }
}
</script>

次のように表示されることを確認します。

さいごに

TS&クラススタイル化した上で、layoutを利用する方法の紹介でした。 一度ベースを作って開発が進んでいくと、当初のベース作りの方法を忘れてしまいがちなので、自分向けの備忘録的にまとめてみました。 同じ用に公式のサンプルをもとにベースを作りたいけどどうすればいいんだっけ?という方の参考になれば幸いです。

参考