💬

Laravel 8でInertia+Vuetifyにvue-cookiesを… - Laravel JetStream - お試し

2021/10/10に公開

はじめに

経緯

Laravel 8でInertia+Vuetifyでテンプレート対応の続きとして、Inertia + Vue + Vuetify でレイアウト構成を組んでみた勢いで vue-cookies を試すことにしたというお話です。

Inertia + Vueでクライアント側の状態管理をするのに、Vuexは使わずに、vue-cookiesを使ってみます。

実現内容

前回作成したレイアウト構成に少し手を加えます。
http://localhost/app02/data-tablesのメニューは<v-navigation-drawers>を利用し、マウスオーバーするまで折りたたみ状態で表示されるexpand-on-hoverをオンにしていました。

この折り畳み状態の切り替えをマウスオーバーではなくクリックで行い、そしてその状態を画面遷移後も維持するようにする、ということをCookieを利用して実現したいと考えました。

VueでCookieを簡単に扱えるようにするため、vue-cookiesを利用します。

CookieなしのUI変更

せっかくなので、まずは実現する内容についてUIのみ変更し、状態管理をしないとどのような挙動になるのか見てみましょう。

※編集の都度ビルドが必要です。予めnpm run watchを実行するなどお忘れなく。

1. メニュー(Drawer)の修正

メニューの開閉状態を格納するプロパティをdata () {}あたりに追加します。(後で消しますが)

resources/js/Commons/Drawer.vue
drawer: true,drawer: true,
miniDrawer: true,

<v-navigation-drawer>expand-on-hoverを以下のように変更します。

resources/js/Commons/Drawer.vue
expand-on-hover

:mini-variant="miniDrawer"

メニューの開閉用のUIを設置するため先頭の<v-list-item>あたりを書き換えます。

resources/js/Commons/Drawer.vue
<v-list-item class="px-3">
  <v-list-item-avatar size="32" color="grey"></v-list-item-avatar>
  <v-list-item-title class="title">メニュー</v-list-item-title>
</v-list-item><v-list-item class="px-3">
  <v-list-item-avatar size="32" color="grey"
      class="cursor-pointer" @click="miniDrawer = !miniDrawer">
  </v-list-item-avatar>
  <v-list-item-title class="title">メニュー</v-list-item-title>
  <v-spacer/>
  <v-btn icon @click="miniDrawer = true">
    <v-icon>mdi-chevron-left</v-icon>
  </v-btn>
</v-list-item>

UI関連の変更はこれくらいです。

2. 動作確認

http://localhost/app02/data-tablesにアクセスして動作確認します。

expand-on-hoverを削除したので、折りたたまれたメニューをマウスオーバーしてもメニューが開かなくなりました。
代わりに、:mini-variant="miniDrawer"あたりの変更により、メニューの左上の<v-list-item-avatar>をクリックすると、メニューが開閉します。

そして、メニューを開いた状態にしてWelcomeをクリックし、画面遷移してみます。
すると、画面遷移後のメニューは閉じた状態になります。

画面遷移した際に、画面の状態も初期化されるため、メニューが閉じた状態になる、というわけです。

この開閉状態を画面遷移後も維持する仕組みを、vue-cookiesで組んでみようと、そんな話です。

vue-cookiesの導入

まずは、vue-cookiesを導入します。
vue-cookiesについてはこちらを参照してください。

1. パッケージインストール

vue-cookiesパッケージをインストールします。

laradock@8896705ba0d1:/var/www/example-app02$ npm install vue-cookies
実行イメージ
added 1 package, and audited 844 packages in 3s

94 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

2. プロジェクトに適用

app.jsを編集し、vue-cookiesをプロジェクトに組み込みます。

resources/js/app.js
import VueCookies from 'vue-cookies';Vue.use(VueCookies);

※必要に応じて、Vue.$cookies.config()で設定も行います。

導入は以上です。

Cookieを管理するミックスインを作成、組み込み

いくつかの方法で実装してみましたが、今回のケースではミックスインに機能をまとめるのが良さそうだったので、この形にしています。(Cookieに保持する情報が異なれば、別の実装の方が良いかもしれません)

※ミックスインについてはこちらを参照してください。

1. ミックスインファイル作成

というわけでresources/js/mixinsディレクトリを作成し、そこにcookie-manager.jsというファイル名でミックスインを作成します。名前はお好みで。

ミックスインファイルの内容はこんな感じに仕立てました。

resources/js/mixins/cookie-manager.js
export default {
  data: () => ({
    cookieManager: {
      miniDrawer: null
    }
  }),
  computed: {
    miniDrawer: {
      get () {
        if (this.cookieManager.miniDrawer === null) {
          return (this.$cookies.get('mini-drawer') === 'close')
        }
        return this.cookieManager.miniDrawer
      },
      set (value) {
        this.$set(this.cookieManager, 'miniDrawer', value)
        this.$cookies.set('mini-drawer', (value ? 'close' : 'open'), Infinity)
      }
    }
  }
}

2. メニュー(Drawer)に組み込み

作成したミックスインをメニューに組み込みます。

まずcookie-manager.jsをimportします。

resources/js/Commons/Drawer.vue
<script><script>
import cookieManager from '@/mixins/cookie-manager'

data () {}あたりに追加したminiDrawerを削除します。

resources/js/Commons/Drawer.vue
miniDrawer: true,

mixins定義を追加して、importしたミックスインを適用します。

resources/js/Commons/Drawer.vue
export default {export default {
  mixins: [cookieManager],
参考:変更後のDrawer.vue
resources/js/Commons/Drawer.vue
<template>
  <v-navigation-drawer
      id="commons-drawer"
      v-model="drawer"
      :mini-variant="miniDrawer"
      permanent
      app>
    <v-layout column>
      <v-list-item class="px-3">
        <v-list-item-avatar size="32" color="grey"
          class="cursor-pointer" @click="miniDrawer = !miniDrawer">
        </v-list-item-avatar>
        <v-list-item-title class="title">メニュー</v-list-item-title>
        <v-spacer/>
        <v-btn icon @click="miniDrawer = true">
          <v-icon>mdi-chevron-left</v-icon>
        </v-btn>
      </v-list-item>

      <v-divider/>

      <template v-for="(link, index) in links">
        <inertia-link :key="index" :href="route(link.name)" as="v-list-item">
          <v-list-item-action>
            <v-icon>{{ link.icon }}</v-icon>
          </v-list-item-action>
          <v-list-item-content>
            <v-list-item-title v-text="link.title" />
          </v-list-item-content>
        </inertia-link>
      </template>

    </v-layout>
  </v-navigation-drawer>
</template>

<script>
import cookieManager from '@/mixins/cookie-manager'

export default {
  mixins: [cookieManager],
  data () {
    return {
      drawer: true,
      links: [{
        name: 'welcome',
        icon: 'mdi-home',
        title: 'Welcome'
      }, {
        name: 'dashboard',
        icon: 'mdi-view-dashboard',
        title: 'Dashboard'
      }, {
        name: 'data-tables',
        icon: 'mdi-view-list',
        title: 'DataTables'
      }],
    }
  }
}
</script>

<style scoped>
</style>

動作確認

再度、http://localhost/app02/data-tablesにアクセスして動作確認します。

メニューを開いた状態にしてWelcomeをクリックし、画面遷移してみます。
今度は、画面遷移後もメニューの状態が維持されます。

画面遷移した際に、メニューの状態をCookieから復元することで、メニューの状態が維持されるというわけです。

まとめ

vue-cookiesを導入して、メニューの状態管理を行ってみました。

vue-cookiesを初めて試してみましたが、インスタンスプロパティ経由でCookieを扱えて、使いやすいパッケージという印象です(そんなものかもしれませんが)。

インスタンスプロパティ経由で扱えはするものの、いたるところにthis.$cookiesが登場するのもどうか、ということでミックスイン化しています。こちらはメニューの状態管理だけでなく他の状態管理も行う想定で組んでみた、というところです。実用はしていないので、もっと検証が必要かもしれません。

今回の記事までで、Vuetify入れて、テンプレート化してみたり、vue-cookiesを試してみたりして、なんとなくInertia + Vueによる実装のイメージはわいてきました。
慣れればSPAとの差をあまり意識せずに実装できる気もします。むしろ、ルート設定を重複管理しなくて済んだり、props経由でデータを渡すことでデータを直感的に扱えるので、メリットの方が大きいのではないかと。
そう考えると、Vuetifyを入れずに、JetStreamの標準コンポーネントで組むのも良いかもしれないとも思います(registerとかconfirm-passwordとか用意されている画面を差し替えるのも大変なので)。

取り急ぎ今回はここまで。

Discussion