pages
app.vue만 사용할 경우 vue-router가 포함되지 않습니다. pages 시스템을 강제로 사용하려면 nuxt.config에서 pages: true를 설정하거나 app/router.options.ts를 추가하세요.사용법
페이지는 Vue 컴포넌트이며 Nuxt가 지원하는 유효한 확장자를 가질 수 있습니다(기본적으로 .vue, .js, .jsx, .mjs, .ts 또는 .tsx).
Nuxt는 ~/pages/ 디렉토리 내의 모든 페이지에 대해 자동으로 라우트를 생성합니다.
<template>
<h1>Index page</h1>
</template>
// https://vuejs.org/guide/extras/render-function.html
export default defineComponent({
render () {
return h('h1', 'Index page')
}
})
// https://nuxt.com/docs/examples/advanced/jsx
// https://vuejs.org/guide/extras/render-function.html#jsx-tsx
export default defineComponent({
render () {
return <h1>Index page</h1>
}
})
pages/index.vue 파일은 애플리케이션의 / 라우트에 매핑됩니다.
app.vue를 사용하는 경우, 현재 페이지를 표시하려면 <NuxtPage/> 컴포넌트를 사용해야 합니다:
<template>
<div>
<!-- 모든 페이지에서 공유되는 마크업, 예: NavBar -->
<NuxtPage />
</div>
</template>
페이지는 반드시 하나의 루트 엘리먼트만 가져야 하며, 페이지 간 라우트 전환을 가능하게 합니다. HTML 주석도 엘리먼트로 간주됩니다.
즉, 라우트가 서버에서 렌더링되거나 정적으로 생성될 때는 내용을 올바르게 볼 수 있지만, 클라이언트 사이드 내비게이션 중 해당 라우트로 이동하면 라우트 전환이 실패하고 해당 라우트가 렌더링되지 않습니다.
다음은 단일 루트 엘리먼트를 가진 페이지의 예시입니다:
<template>
<div>
<!-- 이 페이지는 올바르게 하나의 루트 엘리먼트만 가집니다 -->
Page content
</div>
</template>
<template>
<!-- 이 페이지는 클라이언트 사이드 내비게이션 중 라우트 변경 시 렌더링되지 않습니다. 이 주석 때문입니다 -->
<div>Page content</div>
</template>
<template>
<div>This page</div>
<div>Has more than one root element</div>
<div>And will not render when route changes during client side navigation</div>
</template>
동적 라우트
대괄호 안에 무언가를 넣으면, 동적 라우트 파라미터로 변환됩니다. 여러 파라미터와 동적이 아닌 텍스트를 파일명이나 디렉토리 내에서 혼합하여 사용할 수 있습니다.
파라미터를 _선택적_으로 만들고 싶다면, 이중 대괄호로 감싸야 합니다. 예를 들어, ~/pages/[[slug]]/index.vue 또는 ~/pages/[[slug]].vue는 /와 /test 모두에 매칭됩니다.
-| pages/
---| index.vue
---| users-[group]/
-----| [id].vue
위 예시에서, 컴포넌트 내에서 $route 객체를 통해 group/id에 접근할 수 있습니다:
<template>
<p>{{ $route.params.group }} - {{ $route.params.id }}</p>
</template>
/users-admins/123로 이동하면 다음과 같이 렌더링됩니다:
<p>admins - 123</p>
Composition API를 사용하여 라우트에 접근하고 싶다면, Options API의 this.$route처럼 라우트에 접근할 수 있는 전역 useRoute 함수가 있습니다.
<script setup lang="ts">
const route = useRoute()
if (route.params.group === 'admins' && !route.params.id) {
console.log('경고! 사용자가 인증되었는지 확인하세요!')
}
</script>
/foo/hello 라우트의 경우, ~/pages/foo.vue가 ~/pages/foo/[slug].vue보다 우선합니다. /foo와 /foo/hello를 서로 다른 페이지로 매칭하려면 ~/pages/foo/index.vue와 ~/pages/foo/[slug].vue를 사용하세요.캐치-올 라우트
캐치-올 라우트가 필요하다면 [...slug].vue와 같은 파일명을 사용하여 생성할 수 있습니다. 이 파일은 해당 경로 아래의 모든 라우트와 매칭됩니다.
<template>
<p>{{ $route.params.slug }}</p>
</template>
/hello/world로 이동하면 다음과 같이 렌더링됩니다:
<p>["hello", "world"]</p>
중첩 라우트
<NuxtPage>를 사용하여 중첩 라우트를 표시할 수 있습니다.
예시:
-| pages/
---| parent/
-----| child.vue
---| parent.vue
이 파일 트리는 다음과 같은 라우트를 생성합니다:
[
{
path: '/parent',
component: '~/pages/parent.vue',
name: 'parent',
children: [
{
path: 'child',
component: '~/pages/parent/child.vue',
name: 'parent-child'
}
]
}
]
child.vue 컴포넌트를 표시하려면, pages/parent.vue 내부에 <NuxtPage> 컴포넌트를 삽입해야 합니다:
<template>
<div>
<h1>나는 부모 뷰입니다</h1>
<NuxtPage :foobar="123" />
</div>
</template>
<script setup lang="ts">
const props = defineProps(['foobar'])
console.log(props.foobar)
</script>
자식 라우트 키
<NuxtPage> 컴포넌트가 다시 렌더링되는 시점을 더 세밀하게 제어하고 싶다면, pageKey prop을 통해 문자열이나 함수를 전달하거나, definePageMeta를 통해 key 값을 정의할 수 있습니다:
<template>
<div>
<h1>나는 부모 뷰입니다</h1>
<NuxtPage :page-key="route => route.fullPath" />
</div>
</template>
또는 다음과 같이 할 수도 있습니다:
<script setup lang="ts">
definePageMeta({
key: route => route.fullPath
})
</script>
라우트 그룹
경우에 따라 파일 기반 라우팅에 영향을 주지 않으면서 라우트 집합을 그룹화하고 싶을 수 있습니다. 이를 위해 괄호 - (와 )로 감싼 폴더에 파일을 넣을 수 있습니다.
예시:
-| pages/
---| index.vue
---| (marketing)/
-----| about.vue
-----| contact.vue
이렇게 하면 앱에 /, /about, /contact 페이지가 생성됩니다. marketing 그룹은 URL 구조상 무시됩니다.
페이지 메타데이터
앱의 각 라우트에 대한 메타데이터를 정의하고 싶을 수 있습니다. <script> 또는 <script setup>에서 사용할 수 있는 definePageMeta 매크로를 사용하여 이를 할 수 있습니다:
<script setup lang="ts">
definePageMeta({
title: '나의 홈 페이지'
})
</script>
이 데이터는 앱의 나머지 부분에서 route.meta 객체를 통해 접근할 수 있습니다.
<script setup lang="ts">
const route = useRoute()
console.log(route.meta.title) // 나의 홈 페이지
</script>
중첩 라우트를 사용하는 경우, 이들 라우트의 페이지 메타데이터는 모두 하나의 객체로 병합됩니다. 라우트 메타에 대한 자세한 내용은 vue-router 문서를 참고하세요.
defineEmits나 defineProps(참고: Vue 문서)처럼, definePageMeta는 컴파일러 매크로입니다. 컴포넌트 내에서 참조할 수 없도록 컴파일 시 제거됩니다. 대신, 전달된 메타데이터는 컴포넌트 외부로 끌어올려집니다.
따라서, 페이지 메타 객체는 컴포넌트를 참조할 수 없습니다. 하지만, 임포트된 바인딩이나 로컬에서 정의된 순수 함수는 참조할 수 있습니다.
<script setup lang="ts">
import { someData } from '~/utils/example'
function validateIdParam(route) {
return route.params.id && !isNaN(Number(route.params.id))
}
const title = ref('')
definePageMeta({
validate: validateIdParam,
someData,
title, // 이렇게 하면 안 됩니다. ref가 컴포넌트 밖으로 끌어올려집니다.
})
</script>
특수 메타데이터
물론, 앱 전반에서 자유롭게 사용할 수 있는 메타데이터를 정의할 수 있습니다. 하지만 definePageMeta로 정의된 일부 메타데이터는 특별한 목적을 가집니다:
alias
페이지 별칭을 정의할 수 있습니다. 이를 통해 서로 다른 경로에서 동일한 페이지에 접근할 수 있습니다. vue-router 문서에 정의된 대로 문자열 또는 문자열 배열이 될 수 있습니다.
keepalive
definePageMeta에서 keepalive: true를 설정하면 Nuxt가 페이지를 Vue <KeepAlive> 컴포넌트로 자동 래핑합니다. 예를 들어, 동적 자식 라우트가 있는 부모 라우트에서 라우트 변경 시 페이지 상태를 유지하고 싶을 때 유용합니다.
부모 라우트의 상태를 유지하려면 <NuxtPage keepalive /> 구문을 사용하세요. <KeepAlive>에 전달할 props도 설정할 수 있습니다(전체 목록 보기).
이 속성의 기본값은 nuxt.config에서 설정할 수 있습니다.
key
layout
라우트 렌더링에 사용할 레이아웃을 정의할 수 있습니다. false(레이아웃 비활성화), 문자열, 또는 반응형으로 만들고 싶다면 ref/computed가 될 수 있습니다. 레이아웃에 대해 더 알아보기.
layoutTransition 및 pageTransition
페이지와 레이아웃을 감싸는 <transition> 컴포넌트에 대한 전환 속성을 정의하거나, 해당 라우트에 대해 <transition> 래퍼를 비활성화하려면 false를 전달할 수 있습니다. 전달 가능한 옵션 목록 또는 전환 동작에 대해 더 알아보기를 참고하세요.
이 속성의 기본값은 nuxt.config에서 설정할 수 있습니다.
middleware
이 페이지를 로드하기 전에 적용할 미들웨어를 정의할 수 있습니다. 일치하는 모든 부모/자식 라우트에서 사용된 다른 미들웨어와 병합됩니다. 문자열, 함수(글로벌 before 가드 패턴을 따르는 익명/인라인 미들웨어 함수), 또는 문자열/함수 배열이 될 수 있습니다. 이름이 지정된 미들웨어에 대해 더 알아보기.
name
이 페이지의 라우트에 이름을 정의할 수 있습니다.
path
파일명으로 표현할 수 없는 더 복잡한 패턴이 필요한 경우, 경로 매처를 정의할 수 있습니다. 자세한 내용은 vue-router 문서를 참고하세요.
props
라우트 params를 페이지 컴포넌트에 전달되는 props로 접근할 수 있게 해줍니다. 자세한 내용은 vue-router 문서를 참고하세요.
커스텀 메타데이터 타입 지정
페이지에 커스텀 메타데이터를 추가하는 경우, 타입 안전하게 하고 싶을 수 있습니다. definePageMeta에서 허용하는 객체의 타입을 확장할 수 있습니다:
declare module '#app' {
interface PageMeta {
pageType?: string
}
}
// 타입을 확장할 때는 항상 무언가를 import/export 해야 합니다
export {}
내비게이션
앱의 페이지 간 내비게이션을 위해서는 <NuxtLink> 컴포넌트를 사용해야 합니다.
이 컴포넌트는 Nuxt에 기본 포함되어 있으므로, 다른 컴포넌트처럼 import할 필요가 없습니다.
pages 폴더의 index.vue 페이지로 이동하는 간단한 링크 예시:
<template>
<NuxtLink to="/">Home page</NuxtLink>
</template>
프로그래밍 방식 내비게이션
Nuxt는 navigateTo() 유틸리티 메서드를 통해 프로그래밍 방식의 내비게이션을 허용합니다. 이 유틸리티 메서드를 사용하면 앱 내에서 사용자를 프로그래밍적으로 이동시킬 수 있습니다. 이는 사용자 입력을 받아 동적으로 내비게이션할 때 유용합니다. 아래 예시에서는 사용자가 검색 폼을 제출할 때 호출되는 navigate()라는 간단한 메서드가 있습니다.
navigateTo를 await 하거나 함수에서 반환하여 결과를 체이닝하세요.<script setup lang="ts">
const name = ref('');
const type = ref(1);
function navigate(){
return navigateTo({
path: '/search',
query: {
name: name.value,
type: type.value
}
})
}
</script>
클라이언트 전용 페이지
.client.vue 접미사를 붙여 클라이언트 전용 페이지로 정의할 수 있습니다. 이 페이지의 내용은 서버에서 렌더링되지 않습니다.
서버 전용 페이지
.server.vue 접미사를 붙여 서버 전용 페이지로 정의할 수 있습니다. 클라이언트 사이드 내비게이션(즉, vue-router로 제어)으로 해당 페이지로 이동할 수 있지만, 자동으로 서버 컴포넌트로 렌더링되므로 페이지 렌더링에 필요한 코드는 클라이언트 번들에 포함되지 않습니다.
커스텀 라우팅
앱이 커지고 복잡해질수록 라우팅에 더 많은 유연성이 필요할 수 있습니다. 이를 위해 Nuxt는 라우터, 라우트, 라우터 옵션을 다양한 방식으로 직접 커스터마이즈할 수 있도록 노출합니다.
다중 페이지 디렉토리
기본적으로 모든 페이지는 프로젝트 루트의 하나의 pages 디렉토리에 있어야 합니다.
하지만, Nuxt Layers를 사용하여 앱의 페이지를 그룹화할 수 있습니다:
-| some-app/
---| nuxt.config.ts
---| pages/
-----| app-page.vue
-| nuxt.config.ts
// some-app/nuxt.config.ts
export default defineNuxtConfig({
})
export default defineNuxtConfig({
extends: ['./some-app'],
})