nuxt3.svg

【Nuxt 3】ページの構成について

Nuxt3

基本構成

Nuxt 3では、基本的にレイアウト(Layout)、ページ(Page)、コンポーネント(Component)の3つで1つのページを構成します。 これはNuxt 2のときから変わりありません。

Layout Page Component Component Component

イメージは上図のような感じでしょうか。 レイアウトでヘッダーやサイドメニューのように各ページで共通の部分を作成します。 ページはコンポーネントとして分割した部品で構成し、ルーティングによって切り替わります。

Nuxt 3からはapp.vueが使用できるようになっています。 ここでは<NuxtLayout><NuxtPage>を用いて上記の基本構成の定義します。 下記のような構成を使用する場合、app.vueはプロジェクトから削除していても動作します。

app.vue
<template>
  <div>
    <NuxtLayout>
      <NuxtPage />
    </NuxtLayout>
  </div>
</template>

レイアウトやページが不要な場合は使用する必要はありません。 Nuxtの最小構成としてapp.vueだけでアプリケーションを作成することもできますが、それはNuxtでなくても良いのでは?となりそうですね。

それでは以下よりそれぞれの機能や役割について深掘りしていきます。

ページ

まずはページから説明していきます。 レイアウトやコンポーネントは使用せずともアプリケーションの構築は可能ですが、ページはルーティングの役割を担うのでNuxtを使用する上では必須と言えます。

ルーティング

/pagesフォルダに作成したVueファイルがそのままページの役割を持ったファイルとなります。 ここで重要なのは、/pagesのフォルダ構成がそのままルーティングの設定となることです。 以下は簡単な例になります。

/pages
  ┝ /user
  │  ┝ [id].vue    →  /user/{id}
  │  ┝ edit.vue    →  /user/edit
  │  └ index.vue   →  /user
  ┝ about.vue       →  /about
  └ index.vue       →  /

見ての通りだとは思いますが、フォルダ階層やファイル名によってルーティングが設定されているのがわかるかと思います。

パスパラメータを使用する場合は、ファイル名またはフォルダ名を[]で囲みます。 Nuxt 2では先頭にアンダーバーをつけていましたが、Nuxt 3から変更されていますので注意してください。

またパスの一部をパスパラメータとすることが可能になっています。 例えばuser-[group].vueというファイルを作った場合、[group]の部分がパスパラメータとして扱われます。 具体的に、/user-adminというパスでは、group = 'admin'となります。

パスパラメータの値を含め、ルーティングの情報はuseRoute()で参照します。

<script setup>
const route = useRoute()
const id = route.params.id //パスパラメータ[id]の取得
</script>
  • fullPath:クエリを含めた現在パス
  • path: 現在のパス
  • query:クエリパラメータ
  • params:パスパラメータ
  • name:ルーティングに設定された名前(フォルダ名-ファイル名)

ページ遷移

ページを遷移するには<NuxtLink>を使用します。 例えば/aboutに遷移する場合は以下のように記述します。

<NuxtLink to="/about">about</NuxtLink>

パスが一致するリンクには、router-link-activerouter-link-exact-activeクラスが付与されます。 このクラスによってアクティブなリンクのスタイルを変更します。

Nuxt 2では active と exact active が明確に使い分けられていたのですが、Nuxt 3ではすべて exact active となっているようです。 Nuxt 2のexactプロパティがデフォルトで設定されているような状態です。 しかし、Nuxt 3の<NuxtLink>にはexactプロパティがないのですよね。 スタイル設定をする場合は注意が必要です。

Script上でページ遷移を実行したい場合は、useRouter()を使用します。

const router = useRouter()
router.back()  //1つ戻る
router.forward()  //1つ進む
router.go(1)  //引数の数値分進む(戻る)
router.push('/about')  //指定したパスに遷移
router.replace('/about')  //指定したパスに置換

ただし、push()replace()については、代わりにnavigateTo()を使用することが推奨されています。 navigateTo()は自動インポートされるため、即座に使用することができます。

navigateTo('/about')

navigateTo({
  path: '/about',
  query: {
    param1: 1,
    param2: 'abc'
  }
})

headの設定

<title><meta>をページごとに設定するには、useHead()を使用します。

<script setup>
useHead({
  title: 'About Page',
  meta: [
    { name: 'description', content: 'Aboutのページです。'}
  ]
})
</script>

もう一つ、<Head>を使用する方法があります。 Scriptではなく、Template部分に記述します。

<template>
  <Head>
    <Title>{{ title }}</Title>
    <Meta name="description" :content="description" />
  </Head>
  <div class="contents">
  </div>
</template>

<script setup>
const title = 'About Page'
const description = 'Aboutのページです。'
</script>

middleware

middlewareは、ページがレンダリングされる前に実行したい処理を定義します。 例えば、ページの認可処理などに使用します。 middlewareの処理はページに直接記述することもできますが、 多くは/middlewareフォルダに作成します。

/middleware/auth.js
export default defineNuxtRouteMiddleware((to, from) => {
  const auth = useState('auth')
  if (!auth.value.authenticated) {
    return navigateTo('/login')
  }
})

tofromはそれぞれ遷移後、遷移前のrouteの情報になります。 例えば遷移後のパスパラメータを参照したい場合は、to.params.idとします。

また条件により遷移先を変更する場合は、navigateTo()を使用します。

ページごとにmiddlewareを設定するには、以下のようにdefinePageMeta()を使用します。

<script setup>
definePageMeta({ middleware: 'auth' })
</script>

すべてのページに適用する場合は、/middlewareフォルダにxxxx.global.js(ts)のようにglobalを含めた名前のファイルを作成します。

レイアウト

レイアウトのファイルは、/layoutsフォルダに作成します。 Nuxt 2と同様にデフォルトではdefault.vueの内容が反映されます。

/layouts/default.vue
<template>
  <header>Header</header>
  <main>
    <slot />
  </main>
  <footer>Footer</footer>
</template>

Nuxt 2では、ページの表示部分を<Nuxt />としていましたが、Nuxt 3からは<slot />を使用するようになります。

ページで使用するレイアウトを変更したい場合は、definePageMeta()layoutに設定します。

<script setup>
definePageMeta({ layout: 'other' })
</script>

コンポーネント

最後にコンポーネントについて説明していきます。 コンポーネントは先述したように、ページを構成するための部品を作成するイメージです。 これらは/componentsフォルダに作成していきます。

コンポーネントの読み込み

コンポーネントは自動インポートされるため、簡単に使用することができます。 基本的にコンポーネント名 = ファイル名となります。 例えば/components/MyComponent.vueの場合は、<MyComponent />または<my-component />で使用します。

/components/hoge/MyComponent.vueのようにフォルダ階層を用いる場合は、<HogeMyComponent />とフォルダ名もコンポーネント名に含めます。 フォルダ名をコンポーネント名に含めたくない場合は、以下のようにnuxt.config.jsを設定します。

nuxt.config.js
export default defineNuxtConfig({
  components: [{
    path: '~/components/',
    pathPrefix: false,
  }]
})

useAsyncData, useFetch

Nuxt 2ではasyncDatafetchを用いてレンダリング前に外部からデータを取得していました。 asyncDateはページ専用で、fetchはコンポーネントでも使用することができました。

Nuxt 3からは代わりにuseAsyncDatauseFetchを使用します。 どちらもページに限らずコンポーネントでも使用できます。

これらの詳細についてはまた別の記事で紹介できたらと思っています。

エラーページ

Nuxt 2ではエラーページは/layouts/error.vueに作成していました。 Nuxt 3からはプロジェクトのルートにerror.vueを作成します。

error.vue
<template>
  {{ error.message }}
  <button @click="handleError">clear error</button>
</template>

<script setup>
const props = defineProps({ error: Object })

const handleError = () => clearError({ redirect: '/' })
</script>

エラーの情報はerrorプロパティとして受け取ります。 またエラーページから戻る場合は、clearError()を用い、redirectに戻り先のページのパスを指定します。

意図的にエラーページを表示したい場合は、以下のようにshowError()を使用します。

showError('Error Message!!')