見出し画像

【ララはじ #8】 Laravel9とVue3でだいたいやりたいこと出来ました。

ちょっと、Web系の開発から離れていたので、今時どんな感じになってるのかを確認する為にいろいろやってみた備忘録です。

築山五郎の人生語録より

まぁ、ログイン認証ができて、ページの認証ガードが出来ればいいんじゃないかと思ってたので、最後に、雛形になるところまでやっていきます。あとなんですか、途中で気がついたんですが、今後、Composition API というのを使った記述になるっぽいので、そんな感じで修正します。

まず、認証用にストアを作ります。resources/js/stores/auth.js というファイルにします。

import { ref } from 'vue';
import { defineStore } from 'pinia';

export const useAuthStore = defineStore('auth', () => {
  const authenticated = ref(false);
  const user = ref({});
  function login() {
    axios.get('/api/user').then(({data}) => {
      this.user = data;
      this.authenticated = true;
      this.router.push('/');
    }).catch((e) => {
      this.user = {};
      this.authenticated = false;
    })
  }
  function logout() {
    axios.post('/api/logout').then((res) => {
      this.user = {};
      this.authenticated = false;
      this.router.push('/login');
    });
  }
  return { authenticated, user, login, logout };
});

ここで、Routerをつかって、画面遷移させていますので、piniaの初期化でRouterが使える様、resources/js/app.js に追記します。

import './bootstrap';
import { createApp, markRaw } from "vue";

(中略)

const pinia = createPinia();
pinia.use(({ store }) => {
  store.router = markRaw(router);
});
const vuetify = createVuetify();

(中略)

まぁ公式サイトに載ってますw
次にルートに認証を追加していきます。ファイルはresources/js/router/index.js ですね。

import Login from '@/components/pages/Login.vue';
import Default from '@/components/layouts/Default.vue';
import Dashboard from '@/components/pages/Dashboard.vue';
import UserList from '@/components/pages/UserList.vue';
import NotFound from '@/components/pages/NotFound.vue';
import { useAuthStore } from '@/stores/auth';

const routes = [
  {
    name: "login",
    path: "/login",
    component: Login,
    meta: {
      middleware: "guest",
    },
  },
  {
    path: "/",
    component: Default,
    meta: {
      middleware: "auth",
    },
    children:[
      {
        name: "dashboard",
        path: "",
        component: Dashboard,
      },
      {
        name: "userlist",
        path: "users",
        component: UserList,
      },
    ],
  },
  {
    path: '/:catchAll(.*)',
    component: NotFound,
  },
];

const router = createRouter({
  routes,
  history: createWebHistory(),
});

router.beforeEach((to, from, next) => {
  const auth = useAuthStore();
  if (to.meta.middleware === "guest") {
    if (auth.authenticated) {
      next({ name: "dashboard" })
    } else {
      next()
    }
  } else {
    if (auth.authenticated) {
      next()
    } else {
      next({ name: "login" })
    }
  }
});

export default router;

ちょっと、ページ増えましたが、以前のダッシュボード画面をベースレイアウト(resources/js/components/layouts/Default.vue)になるように、ネスト構成で、新しくダッシュボード(resources/js/components/pages/Dashboard.vue)と一覧表(resources/js/components/pages/UserList.vue)を作成し、存在しないページを指定した場合の画面(resources/js/components/pages/NotFound.vue)を作成しました。ソースは以下になります。

# Default.vue 

<template>
  <v-app>
    <Header></Header>
    <Sidebar></Sidebar>
    <v-main>
      <router-view></router-view>
    </v-main>
    <Footer></Footer>
  </v-app>
</template>

<script setup>
import Header from '@/components/layouts/Header.vue';
import Footer from '@/components/layouts/Footer.vue';
import Sidebar from '@/components/layouts/Sidebar.vue';
</script>
# Dashboard.vue

<template>
  <v-card class="ma-4">
    <v-card-title>
      <h1>Laravel9、さわり始めました。</h1>
    </v-card-title>
  </v-card>
</template>
# UserList.vue
 
<template>
  <v-container>
    <v-row no-gutters>
      <v-col cols="12">
        <v-card class="ma-1">
          <v-card-title>
            <h3>一覧表</h3>
          </v-card-title>
          <v-card-text class="mb-0">
            <v-table>
              <thead>
                <tr>
                  <th class="text-left">
                    ID
                  </th>
                  <th class="text-left">
                    ユーザ名
                  </th>
                  <th class="text-left">
                    メールアドレス
                  </th>
                </tr>
              </thead>
              <tbody>
                <tr
                  v-for="item in items"
                  :key="item.id"
                >
                  <td>{{ item.id }}</td>
                  <td>{{ item.name }}</td>
                  <td>{{ item.email }}</td>
                </tr>
              </tbody>
            </v-table>
          </v-card-text>
        </v-card>
      </v-col>
    </v-row>
  </v-container>
</template>

<script setup>
import { ref, onMounted } from 'vue'

const items = ref([])

async function getUsers() {
  const res = await axios.get('/api/users')
  items.value = res.data;
}

onMounted(() => {
  getUsers()
});
</script>
# NotFound.vue

<template>
  <h1>Oops!</h1>
</template>

あと、ヘッダーにログアウト機能を追加します。ファイルは、resources/js/components/layouts/Header.vue です。

<template>
  <v-app-bar app>
    <v-app-bar-nav-icon @click="layout.toggle">
    </v-app-bar-nav-icon>
    <v-toolbar-title>
      お試しシステム
    </v-toolbar-title>
    <v-menu width="200px">
      <template v-slot:activator="{ props }" v-slot:append>
        <v-btn icon v-bind="props">
          <v-icon>mdi-dots-vertical</v-icon>
        </v-btn>
      </template>
      <v-list
        color="white"
      >
        <v-list-item @click="auth.logout" role="button">
          <template v-slot:prepend>
            <v-icon icon="mdi-account"></v-icon>
          </template>
          <v-list-item-title>ログアウト</v-list-item-title>
        </v-list-item>
      </v-list>
    </v-menu>
  </v-app-bar>
</template>

<script setup>
import { useLayoutStore } from '@/stores/layout'
import { useAuthStore } from '@/stores/auth'

const layout = useLayoutStore();
const auth = useAuthStore();
</script>

サイドバー(resources/js/components/layouts/Sidebar.vue)も変更します。

<template>
  <v-navigation-drawer v-model="layout.isOpenDrawer" app elevation="4">
    <v-list dense nav>
      <v-list-item
        v-for="item in items"
        :key="item.title"
        :to="item.to"
      >
        <template v-slot:prepend>
          <v-icon :icon="item.icon"></v-icon>
        </template>
        <v-list-item-title v-text="item.title"></v-list-item-title>
      </v-list-item>
    </v-list>
  </v-navigation-drawer>
</template>

<script setup>
import { useLayoutStore } from '@/stores/layout'
import { ref } from 'vue';

const layout = useLayoutStore()
const items = ref([
  {
    title: "ダッシュボード",
    icon: "mdi-view-dashboard",
    to: "/"
  },
  {
    title: "一覧表",
    icon: "mdi-table-column-width",
    to: "/users"
  }
])
</script>

あとは一覧表を取得するapiを作成して、Laravel側のrouteに登録すれば、なんとなくできあがりですね。

今回、ソースプログラム多めで、記事としてはどうかと思いますが、
デザイン面と不完全なエラー処理はアレとしても、雛形としては使えそうな気がしてきました。

ちょっと目を離した隙に、世界は色々と変わっていく今日この頃、
以前は出来ていたものを、こういうやり方で再現しつつ学習していくのはいかがでしょうか。

この記事が気に入ったらサポートをしてみませんか?