はじめに
このUIでバニラjsで作るのしんどいからVueコンポーネント使いたい…。けど全体的にbladeで作ってきてるし、このプロジェクトでVueに精通してる人は少ないからSPAにするのは厳しいな…
ということで基本はbladeで、一部Vueのコンポーネントを入れるようにしました。
↓こんな感じで使えるように
例:子blade.php(app.blade.phpのslotに入るところ)
<x-app-layout>
<div>
...
<file-uploader></file-uploader> <!-- Vueコンポーネント-->
Vueをマウントする場所を決める
まずVueコンポーネントを使う範囲を考えて、マウントする場所を決めましょう。その親要素にidを振ります。
ほんとは範囲狭い方が良いんだと思います。
app.blade.php
<head>
...
@vite(['resources/js/app.js']) <!-- app.jsを読み込んでおきましょう! -->
</head>
<body>
<div id="vue-p"><!-- この配下で使えるようにするぜ!-->
<main class="flex-fill bg-light" style="width:80%;">
{{ $slot }}
</main>
</div>
</body>
app.js
コンポーネントだけを登録してマウントしちゃいましょう
app.js
import { createApp } from 'vue';
const app = createApp({}); //ルートコンポーネントは空に!
//コンポーネントを登録
import FileUploader from './components/FileUploader.vue';
app.component('file-uploader', FileUploader);
import Modal from './components/Modal/Modal.vue';
app.component('modal', Modal);
...
app.mount('#vue-p') //さっきのマウントする場所のID
ルートコンポーネントを空にすると、マウント対象のinnerHTML がテンプレートになります。つまり元の
HTML
<div id="vue-p"> ... </div>
の中身がそのまま表示されます。
npm run dev (or build) と リロードをして確認してみましょう
ただし注意点があります!!
大事な注意点
<div id=vue-p> ... </div>
の中身は、Vueのテンプレートとして使われるので、<script></script>
は効きません!その他動的なものとか使えないかも。
回避策
名前付きスコープでvueのマウントの外に出してあげる
子blade.php
<x-app-layout>
<file-uploader></file-uploader>
<x-slot:javascript> <!-- 名前付きスコープ -->
<script>....</script>
</x-slot>
</x-app-layout>
app.blade.php
<body class="font-sans antialiased">
<div id="vue-p">
<main class="flex-fill bg-light" style="width:80%;">
{{ $slot }}
</main>
</div>
<!-- 外ならOK -->
{{ $javascript ?? '' }}
</x-slot>
なんにせよ狭い方が良いですね!
最近はVue使うならSPAか、Inertiaとからしいので、こういう方法は導入時とか訳アリの時だけの方が良いのかな…?と思っています。