開発ブログ

株式会社Nextatのスタッフがお送りする技術コラムメインのブログ。

電話でのお問合わせ 075-744-6842 ([月]-[金] 10:00〜17:00)

  1. top >
  2. 開発ブログ >
  3. PHP >
  4. Laravel >
  5. Laravel+Inertia.js+Vue.jsでSystemMessagesComponentを作ってみた

Laravel+Inertia.js+Vue.jsでSystemMessagesComponentを作ってみた

こんにちは。
ニシザワです。


本日は、Laravel+Inertia.js+Vue.js3でSystemMessageを出す方法を説明していきます。
今回はSystemMessageをComponent化し、共通のLayoutから自動で出せるようにしていきます。
本ブログではLaravelやInertia.js,Vue.jsのインストール方法は説明しません

環境

PHP:8.1
Laravel:9
Node.js:18.14
Inertia.js:0.11.x
@inertiajs/inertia-vue3: 0.6.x
TypeScript:4.9
Vue.js: 3.2.x
bulma:0.9.x

LaravelからSystemMessageをInertia.jsに渡す

Inertia.jsがHandleInertiaRequestsというHTTP Middlewareを用意してくれています
メッセージを渡すところです
HandleInertiaRequests.php

    public function share(Request $request): array
    {
        return array_merge(parent::share($request), [
            'auth' => [
                'user' => $request->user(),
            ],
            'ziggy' => function () use ($request) {
                return array_merge((new Ziggy())->toArray(), [
                    'location' => $request->url(),
                ]);
            },
            'messages' => function () use ($request) {
                $messages = [];
                foreach ($request->session()->all() as $key => $value) {
                    if (!str_contains($key, 'message')) {
                        continue;
                    }
                    $messages[] = [
                        'type' => str_replace('message-', '', $key),
                        'body' => $value
                    ];
                }
                return $messages;
            }
        ]);
    }

shareメソッドで共通の受け渡しが可能です。
今回はmessagesを追加し、type,bodyのオブジェクトとして渡します

        return redirect(route('index'))
            ->with(['message-success' => '作成しました。']);
        return redirect(route('index'))
            ->with(['message-danger' => '作成に失敗しました。']);
使う側は上記の様になります。

SystemMessagesComponentを作成

SystemMessages.vue

<script lang="ts" setup>
import { computed, ref, watch } from "vue";
import { usePage } from "@inertiajs/inertia-vue3";

const AUTO_REMOVE_MILLISECONDS = 5000;
type MessageType = "success" | "danger" | "info" | "warn";
interface Message {
    type: Type;
    body: string;
}
export interface Messages {
    messages?: Message[];
}

const show = ref<boolean>(true);

const messages = computed<Messages>(() => {
    return usePage().props.value.messages as Messages;
});
watch(
    () => messages.value,
    () => {
        show.value = true;
        setTimeout(() => {
            show.value = false;
        }, AUTO_REMOVE_MILLISECONDS);
    }
);
</script>

<template>
    <div v-show="show" class="system-message">
        <div v-for="(message, p) in messages" :key="p">
            <article
                    class="message"
                    :class="{
                    'is-success': message.type === 'success',
                    'is-info': message.type === 'info',
                    'is-warning': message.type === 'warning',
                    'is-danger': message.type === 'danger',
                }"
            >
                <div class="message-body">
                    {{ message.body }}
                </div>
            </article>
        </div>
    </div>
</template>
<style lang="scss">
.system-message {
    width: 100%;
    position: fixed;
    bottom: 0;
    left: 0;
    z-index: 100;
}
</style>

ここでのポイントは同一ページの場合、Inertiaに埋め込まれるpropsが更新されるタイミングで表示したいので
computedを使い変更を受け取れるようにしています。
また、今回は5秒で表示を消すようにしたかったため、v-showの値もpropsが更新された時にtrue,falseを切り替えられる様にしました。
usePageで取得できるpropsの値の更新タイミングを拾うところでハマリポイントだったので覚えておくと良いでしょう。
他のところでも使えると思います。

共通Layoutに作成したSystemMessagesComponentを埋め込む

CommonLayout.vue

<script lang="ts" setup>
import SystemMessages from "../Components/SystemMessages.vue";
</script>
<template>
    <main class="section">
        <slot />
    </main>
    <SystemMessages />
</template>
最後に共通のLayoutに入れてあげると自動的に、LaravelのControllerからmessageが入ってくると表示されるようになります。
結果としては結構簡潔にかけているのですが、かなり苦労したので参考にしてみてください。
TOPに戻る