こんにちは、かつコーチです。
前回はpages/ディレクトリのファイルベースルーティングを解説しました。
今回は、ヘッダーやフッターなど「全ページ共通の見た目」をまとめるlayouts/ディレクトリを扱います。
「ページごとに同じヘッダーをコピペしていませんか」という悩みを、この記事で解決します。
レイアウトとは?
なぜ共通レイアウトが必要なのか
レイアウトとは、複数のページで使い回す共通の枠組みのことです。
ヘッダー・フッター・サイドバーなどが代表例です。
レイアウトを使わないと、すべてのページに同じHTMLを書くことになります。
修正が発生したとき、全ページを1つずつ直す必要が出てきて非効率です。
Nuxtではlayouts/ディレクトリにファイルを置くだけで、この共通化が自動的に行えます。
app.vueとの関係
Nuxtプロジェクトのルートにはapp.vueというファイルがあります。
ここに<NuxtLayout>というコンポーネントを置くことで、レイアウト機能が有効になります。
<!-- app.vue -->
<template>
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
</template>
<NuxtPage />が各ページの中身、<NuxtLayout>がその外側の共通枠、という役割分担です。
基本の書き方
手順1:layouts/default.vueを作る
まずはlayouts/default.vueを作成します。
ファイル名をdefault.vueにすると、何も指定しなくてもこのレイアウトが自動適用されます。
<!-- layouts/default.vue -->
<script setup lang="ts">
const currentYear: number = new Date().getFullYear()
</script>
<template>
<div class="app-layout">
<header>
<h1>かつコーチのサイト</h1>
</header>
<main>
<slot />
</main>
<footer>
<p>© {{ currentYear }} Katsu Coach</p>
</footer>
</div>
</template>
手順2:<slot/>にページの中身が入る
ポイントは<slot />です。
この位置に、各ページ(pages/配下のコンポーネント)の中身が差し込まれます。
headerとfooterはそのまま固定表示され、<slot />の部分だけがページごとに切り替わるイメージです。
つまずきやすい設定・注意点
私が最初につまずいたのはapp.vueの書き忘れです。
layouts/default.vueを作っただけで満足してしまい、app.vue側に<NuxtLayout>を書いていませんでした。
その結果、レイアウトが一切反映されず「ヘッダーが出ない」と数十分悩みました。
layouts/を使うなら、app.vueに<NuxtLayout><NuxtPage /></NuxtLayout>があるか、必ず確認しましょう。
よくあるつまずきポイント・エラー対処
レイアウト名の大文字小文字問題
もう1つ実際にハマったのが、レイアウトファイル名の付け方です。
❌ Before:ファイル名を大文字始まりにする
<!-- layouts/Admin.vue -->
<template>
<div class="admin-layout">
<slot />
</div>
</template>
<script setup lang="ts">
definePageMeta({
layout: "Admin", // 大文字始まりで指定
})
</script>
これを実行すると、期待した管理画面用レイアウトが適用されず、default.vueのままになってしまいました。
コンソールにエラーは出ないため、原因に気づくまで少し時間がかかりました。
✅ After:ファイル名・指定名ともにケバブケース(小文字+ハイフン)にする
<!-- layouts/admin.vue -->
<template>
<div class="admin-layout">
<slot />
</div>
</template>
<script setup lang="ts">
definePageMeta({
layout: "admin", // ファイル名と一致させる
})
</script>
Nuxtはレイアウトファイル名をケバブケースとして扱います。
AdminUser.vueのようなファイルはadmin-userとして登録されるため、指定側もこの表記に合わせる必要があります。
応用・一歩先の使い方
definePageMetaで複数レイアウトを切り替える
サイト内に「通常ページ用」と「管理画面用」など、複数のレイアウトを持たせることもできます。
各ページの<script setup>内でdefinePageMetaを使い、layoutプロパティを指定するだけです。
<!-- pages/admin/index.vue -->
<script setup lang="ts">
definePageMeta({
layout: "admin",
})
</script>
<template>
<div>
<h2>管理画面トップ</h2>
</div>
</template>
このページだけlayouts/admin.vueが使われ、他のページはdefault.vueのままになります。
setPageLayoutで動的に切り替える
ログイン状態などに応じて、実行時にレイアウトを切り替えたい場合はsetPageLayout関数が便利です。
<script setup lang="ts">
const isLoggedIn = ref<boolean>(true)
if (isLoggedIn.value) {
setPageLayout("member")
}
</script>
definePageMetaが「静的な指定」なのに対し、setPageLayoutは条件分岐など「動的な切り替え」に向いています。
レイアウトを一切使わないページには、layout: falseを指定することも可能です。
まとめ
この記事のポイント
layouts/default.vueを作ると、何も指定しなくても共通レイアウトが自動適用されるapp.vueに<NuxtLayout><NuxtPage /></NuxtLayout>を書かないとレイアウトは反映されない- レイアウトファイル名はケバブケースで扱われるため、
definePageMetaの指定名もそれに合わせる - 複数レイアウトは
definePageMeta({ layout: '名前' })、動的な切り替えはsetPageLayoutを使う
次に読むべき記事
レイアウトの基本を押さえたら、次は[id].vueなどを使った動的ルートの書き方を学んでいきましょう。
→ 次の記事:動的ルート・ネストされたルートの書き方
タグ: Nuxt.js, 初心者向け, ルーティング