「Nuxt.jsのlayoutに各pageから変数を渡す」
とても簡単そうなことですが、調べてもあまり情報がなくて意外に時間をかかったので紹介します。
やりたいこと
下記ディレクトリ構成で、layoutに全ページ共通のヘッダーを設置し、ヘッダーに表示するタイトルを、ページごとに設定をしたかったです。
調べたところEventListenerを使う方法(*1)、Vuexを使う方法などがありましたが、どちらも理想の使いやすさではなかったので、Vue Routerで行う方法を考えました。
ディレクトリ構成
layouts
|- default.vue
components
|- organisms
|- CommonHeader.vue
pages
|- index.vue
layouts/default.vue
<template>
<div>
<common-header title="タイトル" />
<nuxt />
</div>
</template>
<script>
import CommonHeader from '@/components/organisms/CommonHeader'
export default {
components: { CommonHeader },
}
</script>
components/organisms/CommonHeader.vue
organismsというフォルダ名はAtomic Designを採用した構成です。 (*2)
<template>
<header class="header">
<div class="header-leftSide">ロゴ画像</div>
<h1 class="header-title">{{ title }}</h1>
<div class="header-rightSide">メニュー</div>
</header>
</template>
<script>
export default {
props: {
title: { type: String, default: '' },
},
}
</script>
<style lang="scss" scoped>
.header {
display: flex;
justify-content: space-between;
// ...省略
}
</style>
pages/index.vue
<template>
<div>省略</div>
</template>
<script>
export default {
head() {
return {
title: 'TOPページ',
}
},
}
</script>
解決方法
Vue Routerでマッチしたコンポーネントを取得し、コンポーネント内で定義した変数を取得します。
<!-- layouts/default.vue -->
<template>
<div>
<common-header title="title" />
<nuxt />
</div>
</template>
<script>
import CommonHeader from '@/components/organisms/CommonHeader'
export default {
components: { CommonHeader },
computed: {
title() {
const matchedRoute = this.$route.matched[0] // マッチしたrouteを取得
const headInfo = matchedRoute.components.default.options.head() // 該当routeのdefault componentのhead情報を取得
return headInfo ? headInfo.title : ''
},
}
</script>
注意点
- ネストされたルートの場合、複数のルートにマッチする(親コンポネントが最初にマッチされる)ので、上記のコードを少し変更する必要があります。
終わりに
この方法で「理解しやすさ」と「使いやすさ」の目標を達成したと思いますが、もっといい方法があるかな?
他にいい方法がありましたら、ぜひコメントしてください。