LaravelでVuetifyのDrawerメニューで管理画面作成

LaravelでVue.js用のUIコンポーネントライブラリを利用できるUIフレームワークVuetifyをインストールし、VuetifyのDrawerメニューを利用してレスポンシブな管理画面のレイアウトを作成してみます。

開発環境

Laradock v10
Laravel 7
Vue 2.6

Vuetifyインストール

# npm install vuetify
import Vuetify from 'vuetify';
import 'vuetify/dist/vuetify.min.css';
Vue.use(Vuetify);

const app = new Vue({
    el: '#app',  
    vuetify: new Vuetify()
});

Vuetify Drawerで管理画面

参考にするVuetifyのUIコンポーネントのAPIとサンプルは公式サイト
https://vuetifyjs.com/ja/
から「はじめよう」をクリックしたページの左メニュー「UIコンポーネント」にあります。

作成するファイルのディレクトリ構成は以下のようになります。

resources
 ┣ js
 ┃ ┣ components
 ┃ ┃ ┗ User
 ┃ ┃    ┣ FooterComponent.vue
 ┃ ┃    ┣ HeaderComponent.vue
 ┃ ┃    ┣ HomeComponent.vue
 ┃ ┗ app.js
 ┗ views
    ┣ layouts
    ┃ ┗ user.blade.php
    ┗ user
       ┗ home.blade.php

レイアウト

管理画面共通のBladeのレイアウトとして元々存在するresources/views/layouts/app.blade.phpをコピーしてuser.blade.phpを作成しましょう。

・VuetifyはGoogleのRobotoフォントとMaterial design Iconsを使用するのでCDNを追加しましょう。
・ユーザ用のスタイルシートとしてpublic/css/user.cssを作成して読み込むようにしておきます。
・Vuetifyはの中に記述しなければならないのでここで設定しておきます。
・ヘッダーコンポーネントとフッターコンポーネントを追加します。
・<v-content><v-container>内にコンテンツを記述することにします。

<!-- Fonts に追加 -->
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/@mdi/font@4.x/css/materialdesignicons.min.css" rel="stylesheet">

<!-- Styles に追加 -->
<link href="{{ asset('css/user.css') }}" rel="stylesheet">

・・・

<body>
  <div id="app">
    <v-app>
      <user-header-component></user-header-component>
      <v-content>
        <v-container>
          @yield('content')
        </v-container>
      </v-content>
      <user-footer-component></user-footer-component>
    </v-app>
  </div>
</body>

ユーザホームのBladeテンプレートを変更

resources/views/layouts/user.blade.phpを継承し、コンテンツとしてUserHomeComponent.vueを読み込むようにします。

@extends('layouts.user')

@section('content')
    <user-home-component></user-home-component>
@endsection

ヘッダーコンポーネント

Navigation drawer のサンプル:色付きドロワーのの中身にBars/App bars のサンプル:ナビゲーションドロワーの切り替えのだけを組み込みます。
ユーザのコンポーネントなのでUserディレクトリを作成してその直下に配置しておきます。

<template>の中は1つのタグにまとめなければならないのでタグでまとめます。

<template>
<div>

  <!-- Bars/App bars の v-app-bar -->
  <v-app-bar color="primary" dark app clipped-left>
    <v-app-bar-nav-icon @click="drawer=!drawer"></v-app-bar-nav-icon>
    <v-toolbar-title>Vuetify</v-toolbar-title>
  </v-app-bar>

  <!-- 色付きドロワー -->
  <v-navigation-drawer
    app
    v-model="drawer"
    clipped
    class="deep-purple accent-4"
    dark
  >
    <v-list>
      <v-list-item
        v-for="item in items"
        :key="item.title"
        :href="item.to"
        link
      >
        <v-list-item-icon>
          <v-icon>{{ item.icon }}</v-icon>
        </v-list-item-icon>
        <v-list-item-content>
          <v-list-item-title>{{ item.title }}</v-list-item-title>
        </v-list-item-content>
      </v-list-item>
    </v-list>
    <template v-slot:append>
      <div class="pa-2">
        <v-btn block v-on:click="logout">Logout</v-btn>
        <form id="logout-form" action="/logout" method="POST" style="display: none;">
        <input type="hidden" name="_token" :value=csrf_token>
        </form>
      </div>
    </template>
  </v-navigation-drawer>

</div>
</template>


<script>
  export default {
    data () {
      return {
        drawer: null,
        items: [
          { title: 'Dashboard', icon: 'mdi-view-dashboard', to: "/user" },
          { title: 'Account', icon: 'mdi-account-box', to: "#" },
          { title: 'Admin', icon: 'mdi-gavel', to: "#" },
        ],
        csrf_token: document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
      }
    },
    methods: {
      logout() {
        document.getElementById('logout-form').submit();
      },
    },
  }
</script>

<v-app-bar>
・「app」でヘッダーとしてレイアウトしてNavigation Drawerとの関係を良しなにしてくれます。
・「clipped-left」で左端に固定します。

<v-navigation-drawer>
・「app」でメニューとしてレイアウトしてコンテンツ等との関係を良しなにしてくれます。
・「v-model=”drawer”」はv-app-barのv-app-bar-nav-iconと連動してメニューの開閉を制御します。
・「clipped」でv-app-barの下に配置します。
・「absolule」と「temporary」は削除します。

ドロワーメニューのリンク設定
・<v-list-item>の「:href=”item.to”」でリンク先に移動できるようにitemsの要素に「to」を追加してリンク先を設定します。
・vue-routerを使用するSPAサイトでは「:to=”item.to”」とします。

ログアウトボタンの設定
・ログアウトのFormを設置
・Postだとcsrf_tokenが必要になるのでデータオフジェクトとして設定
・logoutメソッドを追加

メニューのアイコン
アイコンがサンプルのままでは正常に表示されないかもしれません。
https://dev.materialdesignicons.com/icons
から適当なアイコンを探してmdi-を付けて指定しましょう。

フッターコンポーネント

Footerのサンプル:Padless Footerを参考に作成します。
これもユーザのコンポーネントなのでUserディレクトリを作成してその直下に配置しておきます。

<template>
  <v-footer
    absolute
    padless
  >
    <v-col
      class="text-center"
      cols="12"
    >
      {{ new Date().getFullYear() }} — <strong>Vuetify</strong>
    </v-col>
  </v-footer>
</template>

「absolute」を設定することでコンテンツ最下部固定になります。

代わりに「app」を設定すると最下部に常時表示にしてくれます。

ユーザホームコンポーネント

ユーザホームのコンテンツを作ります。
<div>でまとめます。

<template>
<div>
  <h1>UserHome</h1>
  <p>Test</p>
</div>
</template>

コンポーネントを登録

Vue.component('user-header-component', require('./components/User/HeaderComponent.vue').default);
Vue.component('user-footer-component', require('./components/User/FooterComponent.vue').default);
Vue.component('user-home-component', require('./components/User/HomeComponent.vue').default);

コンパイル

Vue関連の変更は自動反映させます。

# npm run watch

CSSでデザイン調整

スクロールバーが常時表示されるようになっているのを自動表示に変更します。

html {
  overflow: auto !important;
}

完成

laravel-vuetify-drawer

後記

LaravelでVue.jsのUIフレームワークVuetifyを使用して管理画面のレイアウトを作成しました。
公式サイトのUIコンポーネントサンプルをコピペ&編集で簡単に利用できます。
それぞれのコンポーネントに設定できるプロパティはAPIにまとめられているのでチェックしておきましょう。