イントロダクション
Vueの標準アプリと同様に、Nuxtアプリでもレイアウト、コンポーネント、コンポーザブルを追加することができます。標準的なVueアプリでは /layouts/, /components/, /composables/ ディレクトリを用意することは必須のルールではありませんが、Nuxtが自動的にインポートしてくれるようにするため、Nuxtではこれらのディレクトリをプロジェクトルートに作成しておく必要があります。Nuxtには <NuxtLayout> コンポーネントが付属しており、これを使用するとページ上のレイアウトを動的にレンダリングすることができます。しかし、このコンポーネントには色々と制約があるので調べてみましょう。
レイアウトの作成と変更
Nuxtが提供するレイアウトソリューションがニーズに合っていれば、Nuxtでレイアウトを追加することは標準的なVueアプリよりも簡単です。Nuxt の <NuxtLayout> コンポーネントを使用すると、 /layouts/ ディレクトリから default.vue というレイアウトを自動的にロードすることができます。この <NuxtLayout> コンポーネントを使用すると、任意のページでレイアウトを動的に変更することができます(これもニーズに合わせて)。しかし、このコンポーネントを使用して動的にレイアウトを変更することには、いくつかの欠点があります。以下の手順とオプションで確認してみましょう。
- app.vue ファイルに <NuxtLayout> コンポーネントを挿入します。app.vuevue
<template> <NuxtLayout> <div> <ul v-if="menu"> //... </ul> <NuxtPage/> </div> </NuxtLayout> </template>
- レイアウトを /layouts/ ディレクトリに追加します。
layouts ├── default.vue ├── light.vue └── dark.vue
- 各レイアウトに、<slot /> コンポーネントを含む簡単な構造を追加します。layouts/default.vuevue
<template> <p>default</p> <slot /> </template>
その結果、アプリを実行すると、どのページに移動してもデフォルトで default レイアウトが <NuxtLayout> コンポーネントに読み込まれていることがわかるでしょう。もし、他のページのレイアウトを light や dark に変更したい場合は、必要性に応じて以下のオプションのいずれかを選択することができます。
- コンポーネント自体でレイアウトを変更する。
コンポーネント自体でレイアウトを変更する: <NuxtLayout> コンポーネントに name 属性を追加して、 layout リアクティブオブジェクトを割り当て、テンプレートのコンテンツを囲むようにします。pages/blog/[slugvue<template> <NuxtLayout :name="layout"> // ... </NuxtLayout> </template>
以下のように、<script setup> ブロックで layout リアクティブオブジェクトを作成し、リモート API からページデータを取得し、その結果からレイアウトデータを入力します。pages/blog/[slugvue<script setup> const route = useRoute() const layout = ref(null) const config = useRuntimeConfig() const { data } = await useFetch(`/posts/posts__${route.params.slug}__index`, { baseURL: config.BASE_URL }) layout.value = data.value.layout </script>
このオプションでは、lightまたはdarkレイアウトが default レイアウトの <slot> コンポーネントに読み込まれることが確認できます。デフォルトレイアウトの <slot> コンポーネントの外にあるもの、例えば default は、これらのページにまたがって共有されます。 - トップレベル(親)コンポーネントのレイアウト変更
definePageMetaを使用して、子コンポーネントに手動で/任意でレイアウトを設定します。pages/about.vuevue<script> definePageMeta({ layout: 'light', }) </script>
このオプションを使用すると、 light または dark レイアウトが完全に default レイアウトに置き換わります。しかし、このオプションの欠点は、<script setup> ブロックの layout オプションにレイアウト名を手動で設定する必要があることです。言い換えれば、このオプションのレイアウトは動的に変更することができません。
SSRでもSPAでも、上から下へ動的にレイアウトを変更するほうが簡単です。つまり、親ページ(app.vue)ではなく、子ページ自体に <NuxtLayout> コンポーネントまたは動的コンポーネントを使用すれば、ローカライズされた小さなレイアウトをトップダウンで動的に変更することができます
コンポーネントの作成とインポート
Nuxtでは /components/ ディレクトリを作成して、そこにすべてのコンポーネントを配置するだけで、自動的にインポートされます。コンポーネントはネストされたフォルダに整理することができ、Nuxtはそのフォルダを基にコンポーネントをインポートします。
- /components/ ディレクトリを作成し、例えば input-demo.vueというコンポーネントを作りましょう。
components ├── ... └── input-demo.vue
- 作成したコンポーネントのリアクティブオブジェクトを宣言します。pages/contact.vuevue
<script setup> const username = ref(null) // ... </script>
- 例えば、v-modelディレクティブを入れたテンプレートでコンポーネントを作成します。pages/contact.vuevue
<template> <input-demo type="text" name="username" v-bind:modelValue="username" v-on:update:modelValue="username = $event" /> <p>username: {{ username }}</p> </template>
- /components/ に checkbox サブディレクトリを作成し、 group-xyz.vue をこのサブディレクトリに作成してください。checkbox-demo.vueは、**/components/**ディレクトリ直下におきます。
components ├── ... ├── checkbox-demo.vue └── checkbox └── group-demo.vue
- 先行するチェックボックスコンポーネント用に subscribe と picked のリアクティブオブジェクトを作成します。pages/contact.vuevue
<script setup> // ... const subscribe = ref(false) const picked = ref(['foo', 'bar']) </script>
- テンプレートで checkbox-demo コンポーネントを使用します。pages/contact.vuevue
<checkbox-demo label="Subscribe" v-model="subscribe" true-value="yes" /> <p>subscribe (true or false): {{ subscribe }}</p>
- テンプレートでは、checkboxgroup-demo コンポーネントを CheckboxGroupDemo として代わりに使用します。pages/contact.vuevue
<CheckboxGroupDemo name="group-abc" label="Foo" value="foo" v-model="picked" /> <CheckboxGroupDemo name="group-abc" label="Bar" value="bar" v-model="picked" /> <CheckboxGroupDemo name="group-abc" label="Baz" value="baz" v-model="picked" /> <p>picked (selected checkboxes): {{ picked }}</p>
気をつけなければいけないのは、ネストされたサブディレクトリに編成されているコンポーネントには、キャメルケースを使用する必要があります。
このように、Nuxtではカスタムコンポーネントを非常に簡単に使用することができます。Nuxtはカスタムコンポーネントであっても、これまで紹介してきた <NuxtPage> や <NuxtLayout> コンポーネントのようなNuxt自身のデフォルトコンポーネントであっても、キャメルケースを好むことにお気づきでしょうか。また、Nuxtはクライアントサイドのコンポーネントをレンダリングするために <ClientOnly> コンポーネントも提供しています。https://nuxt.com/docs/guide/directory-structure/components#clientonly-component で確認することができます。これらのコンポーネントではキャメルケースを使用する必要があることに注意してください。
コンポーザブルの作成とインポート
コンポーネントと同様に、Nuxtではローカルで作成したComposablesのインポートが標準的なVueアプリよりも簡単です。/composables/ ディレクトリを作成して、そこにすべての composables .js/.ts ファイルを配置するだけで、Nuxt が自動的にインポートしてくれます。次のステップでNuxtアプリにコンポーザブルを作成してみましょう。
- useA, useB, useC という名前の関数と、useD という定数を作成し、これらの関数を無名の export default 関数と一緒に次のようにエクスポートします。composables/use-foo.jsjs
export function useA () { return 'a' } function useB () { return 'b' } function useC () { return 'c' } export const useD = () => { return 'd' } export { useB, useC } export default function () { return 'bar' }
- 上記のコンポーザブルをインポートせずに、任意のページで直接使用します。pages/index.vuevue
<script setup> const a = useA() const b = useB() const c = useC() const d = useD() const foo = useFoo() </script>
- 以下のように、テンプレートにコンポーザブルの値を表示させます。pages/index.vuevue
<template> <div> <p>Named export <code>useA</code> : {{ a }}</p> <p>Named export <code>useB</code> : {{ b }}</p> <p>Named export <code>useC</code> : {{ c }}</p> <p>Named export <code>useD</code> : {{ d }}</p> <p>Default export <code>useFoo</code> : {{ foo }}</p> </div> </template>
これでOKです。Nuxtでコンポーザブルの作成と インポート が簡単にできましたね。Nuxtの自動インポートを利用すると、何も設定しなくても開発プロセスが速くなり、開発体験がより良いものになります。Nuxtのオートインポートの詳細については、https://nuxt.com/docs/guide/concepts/auto-importsを参照してください。
まとめ
Nuxt は <NuxtLayout> コンポーネントを用いてサーバとクライアントで動的にレイアウトをレンダリングするためのシームレスなデフォルトソリューションを提供します。レイアウトの変更はボトムアップではなく、トップダウンで行うことが推奨されています。Nuxtでコンポーネントやコンパイラを追加するのはとても簡単です。Nuxtは整理したフォルダに基づいてコンポーネント名を生成することもできます。ただ一つ注意しなければならないのは、Nuxtは整理されたコンポーネントにキャメルケースを使用することです。