Nuxt๋ pagesํด๋๋ฅผ ๊ธฐ์ค์ผ๋ก ๋ผ์ฐํ
๋๋ค.
(src/pages/index.vue๊ฐ "/" ๋ฉ์ธ ๊ฒฝ๋ก์)
/ โ pages/index.vue
/about โ pages/about/index.vue
pages/lesson/[title].vue
| pages/
---| lesson/
-----| [title].vue
/* pages/lesson/[title].vue */
<script setup lang="ts"></script>
<template>
<div>
<h2>Lesson</h2>
<p>
Chapter slug: <span>{{ $route.params.title }}๐ต</span>
</p>
</div>
</template>
<style scoped></style>
/* pages/index.vue */
<script lang="ts" setup>
import { greeting } from '@app/ui';
const route = useRoute();
const lessonArr = [
{ id: 1, title: 'vocal' },
{ id: 2, title: 'piano' },
{ id: 3, title: 'rock' },
{ id: 4, title: 'drum' },
];
</script>
<template>
<div>
<p>{{ greeting }}</p>
<br />
<NuxtLink
v-for="lesson in lessonArr"
:key="lesson.id"
:to="`/lesson/${lesson.title}`"
class="text-blue-700"
><p>{{ lesson.title }}</p>
</NuxtLink>
<p>
ํ์ฌ ๊ฒฝ๋ก: <code>{{ route.path }}</code>
</p>
</div>
</template>
<style lang="scss" scoped></style>
โ ์ฐธ๊ณ ) ๋งค๊ฐ๋ณ์๋ฅผ ์ ํ์ฌํญ์ผ๋ก ์ง์ ํ๋ ค๋ฉด ๋งค๊ฐ๋ณ์๋ฅผ ์ด์ค ๋๊ดํธ๋ก ๋ฌถ์ด์ผ ํ๋ค.
pages/lesson/[[title]].vue
pages/[[slug]]/index.vue
๋ pages/[[slug]].vue
์ ๊ฐ๋ค.
ํน์ ๊ฒฝ๋ก ํ์์ ๋ชจ๋ ๊ฒฝ๋ก๋ฅผ ์ฒ๋ฆฌํ ์ ์๋ ๋ผ์ฐํ
๊ธฐ๋ฒ์ด๋ค.
์ด๋ค ๊ฒฝ๋ก๋ ํด๋น ๋ผ์ฐํธ์์ ์ฒ๋ฆฌํ ์ ์๋ค.
[...slug].vue
์ ๊ฐ์ ํ์ด์ง ์ปดํฌ๋ํธ ์ด๋ฆ์ ์ฌ์ฉํ์ฌ ๊ฒฝ๋ก๋ฅผ ๋ง๋ค๋ฉด ๋๋ค.
pages/[...slug].vue
<template>
<p>{{ $route.params.slug }}</p>
</template>
/bt21/tata๋ก ์ด๋ํ๋ฉด ์๋์ ๊ฐ์ด ๋ณด์ฌ์ง๋ค.
<p>["bt21", "tata"]</p>
๊ฒฝ๋ก ์ด๋์ด ๊ฐ๋ฅํ๋ค.
<NuxtLink to="/profile">my profile</NuxtLink>
๊ฒฝ๋ก ์ด๋
<script setup>
const router = useRouter()
</script>
back()
: ๋ค๋ก๊ฐ๊ธฐ router.go(-1)์ ๋์ผํจ.
forward()
: ์์ผ๋ก๊ฐ๊ธฐ router.go(1)์ ๋์ผํจ.
push()
: ์ URL๋ก ์ด๋
replace()
: ํ์ฌ ๊ฒฝ๋ก ์ URL๋ก ์๋ก ๊ณ ์นจ
const router = useRouter()
router.addRoute({ name: 'home', path: '/home', component: Home })
router.removeRoute('home')
router.getRoutes()
router.hasRoute('home')
router.resolve({ name: 'home' })
ํ ํ๋ฆฟ ๋ด์ ๋ผ์ฐํฐ ์ธ์คํด์ค๋ง ํ์ํ ๊ฒฝ์ฐ
<template>
<button @click="$router.back()">Back</button>
</template>
๊ฒฝ๋ก ์ด๋
<script setup lang="ts">
await navigateTo('/search')
await navigateTo({ path: '/search' })
await navigateTo({
path: '/search',
query: {
page: 1,
sort: 'asc'
}
})
</script>
ํ์ฌ ๊ฒฝ๋ก๋ฅผ ๋ฐํ
<script setup lang="ts">
const route = useRoute()
</script>
<template>
<p>ํ์ฌ ๊ฒฝ๋ก: {{ route.path }}</p>
</template>
fullPath
: ๊ฒฝ๋ก, ์ฟผ๋ฆฌ ๋ฐ ํด์๋ฅผ ํฌํจํ๋ ํ์ฌ ๊ฒฝ๋ก์ ์ฐ๊ฒฐ๋ ์ธ์ฝ๋ฉ๋ URL
hash
: #์ผ๋ก ์์ํ๋ URL์ ๋์ฝ๋ฉ๋ ํด์ ์น์
matched
: ํ์ฌ ๊ฒฝ๋ก ์์น์ ์ผ์นํ๋ ์ ๊ทํ๋ ๊ฒฝ๋ก ๋ฐฐ์ด
meta
: ๋ ์ฝ๋์ ์ฒจ๋ถ๋ ์ฌ์ฉ์ ์ ์ ๋ฐ์ดํฐ
name
: ๊ฒฝ๋ก ๋ ์ฝ๋์ ๊ณ ์ ์ด๋ฆ
path
: URL์ ์ธ์ฝ๋ฉ๋ ๊ฒฝ๋ก ์ด๋ฆ ์น์
redirectedFrom
: ํ์ฌ ๊ฒฝ๋ก ์์น์ ๋๋ฌํ๊ธฐ ์ ์ ์ ๊ทผ์ ์๋ํ ๊ฒฝ๋ก ์์น
ํ ํ๋ฆฟ ๋ด์ ๋ผ์ฐํธ ์ธ์คํด์ค๋ง ํ์ํ ๊ฒฝ์ฐ
<template>
<p>ํ์ฌ ๊ฒฝ๋ก: {{ $route.path }}</p>
</template>
layouts
layouts ์์
layouts ์ ์ ๋ฆฌ๋ ๋ธ๋ก๊ทธ
src/layouts/default.vue
/* src/layouts/default.vue */
<script lang="ts" setup></script>
<template>
<div class="h-[50px] flex items-center justify-center w-full fixed bg-black">
<p class="text-cyan-500">~๊ธฐ๋ณธ ๋ ์ด์์~</p>
</div>
<div class="h-screen flex-col flex justify-center items-center">
<slot /> // โญ๏ธ ๊ผญ ์ถ๊ฐ
</div>
</template>
<style scoped></style>
์ปค์คํ layout
-| layouts/
---| default.vue
---| custom.vue
/* layouts/custom.vue */
<script setup lang="ts">
import Header from '@/components/Header/Header.vue';
</script>
<template>
<div>
// ํค๋ => Header์ปดํฌ๋ํธ
<Header />
<slot></slot>
</div>
</template>
/* pages/about/index.vue */
<script setup lang="ts">
definePageMeta({
layout: 'custom'
})
</script>
๋ชจ๋ฐ์ผ์์ ์น์ฌ์ดํธ ํ๋ฉด ํ๋ ์ ๋๊ฒ ํ๋ ๋ฐฉ๋ฒ
export default defineNuxtConfig({
app: {
head: {
charset: 'utf-8',
viewport: 'width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no',
},
},
<script setup lang="ts">
useSeoMeta({
title: 'My Amazing Site',
ogTitle: 'My Amazing Site',
description: 'This is my amazing site, let me tell you all about it.',
ogDescription: 'This is my amazing site, let me tell you all about it.',
ogImage: 'https://example.com/image.png',
twitterCard: 'summary_large_image',
})
</script>
๋ฐ์ํ ํ๊ทธ์ผ ๊ฒฝ์ฐ
<script setup lang="ts">
const title = ref('My title')
useSeoMeta({
title,
description: () => `description: ${title.value}`
})
</script>
useAsyncData๋ณด๋ค ์ฌ์ฉ๋ฒ์ด ๊ฐ๋จํ๋ค.
const { data: product, pending, error } = await useFetch(() => `https://dummyjson.com/products/${id.value}`)
const { data: product, pending, error } = await useAsyncData(() => {
return $fetch(`https://dummyjson.com/products/${id.value}`)
}, {
watch: [id]
})
<script setup>
const id = ref(1)
const { data: product, pending, error } = await useFetch(() => `https://dummyjson.com/products/${id.value}`)
/* Same as:
const { data: product, pending, error } = await useAsyncData(() => {
return $fetch(`https://dummyjson.com/products/${id.value}`)
}, {
watch: [id]
})
*/
</script>
<template>
<div>
<p>Result of <code>https://dummyjson.com/products/</code><input type="number" v-model="id" /></p>
<p><button @click="id--">Previous</button> - <button @click="id++">Next</button></p>
<p v-if="pending">Fetching...</p>
<pre v-else-if="error">{{ error }}</pre>
<pre v-else>{{ product }}</pre>
<NuxtLink to="/">Back home</NuxtLink>
</div>
</template>
defineNuxtConfig({
ssr: false,
nitro: {
prerender: {
routes: ['/', '/e-book'], // SSG ์ ์ฉํ ํ์ด์ง ๊ฒฝ๋ก ์ ๋ ๊ณณ
}
}
})
์ปดํฌ๋ํธ๋ฅผ ํด๋ผ์ด์ธํธ ์ธก์์๋ง ๋ ๋๋งํ๋ค.
<ClientOnly>
<Comment />
</ClientOnly>
๋๋ ํ์ผ ์ด๋ฆ์ .client
๋ฅผ ๋ถ์ฌ ํด๋ผ์ด์ธํธ ์ธก์์๋ง ๋ ๋๋ง์ด ๋๋๋ก ํ ์ ์๋ค.
| components/
--| Comments.client.vue
/* Comments.client.vue */
<template>
<div>
// this component will only be rendered on client side
<Comments />
</div>
</template>
โ๏ธ์ฃผ์) .client๊ตฌ์ฑ ์์๋ ๋ง์ดํธ๋ ํ์๋ง ๋ ๋๋ง ๋๋ค. ๋ ๋๋ง๋ ํ
ํ๋ฆฟ์ ์ฌ์ฉํ๋ ค๋ฉด onMounted()ํ
์ .await nextTick()์ ์ถ๊ฐํ๋ฉด ๋จ.