Vue Router 기초
Vue Router는 Vue.js의 공식 라우팅 라이브러리입니다. URL과 컴포넌트를 매핑하여 SPA(Single Page Application)의 페이지 전환을 처리합니다.
면접에서 "SPA의 라우팅은 어떻게 동작하나요?"라고 물어보면, History API와 해시 모드 의 차이를 설명할 수 있어야 합니다.
설치와 기본 설정
// router/index.ts
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '@/views/HomeView.vue'
const router = createRouter({
// HTML5 History 모드 — 깔끔한 URL (/about)
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'home',
component: HomeView
},
{
path: '/about',
name: 'about',
// 지연 로딩 — 코드 분할
component: () => import('@/views/AboutView.vue')
},
{
path: '/users',
name: 'users',
component: () => import('@/views/UsersView.vue')
}
]
})
export default router
// main.ts
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
createApp(App).use(router).mount('#app')
RouterView와 RouterLink
<!-- App.vue -->
<script setup lang="ts">
import { RouterLink, RouterView } from 'vue-router'
</script>
<template>
<nav>
<!-- RouterLink — 클릭 시 히스토리 API로 네비게이션 (페이지 리로드 없음) -->
<RouterLink to="/">홈</RouterLink>
<RouterLink to="/about">소개</RouterLink>
<RouterLink :to="{ name: 'users' }">사용자</RouterLink>
<!-- active 클래스 자동 적용 -->
<!-- router-link-active: 부분 매칭, router-link-exact-active: 정확한 매칭 -->
</nav>
<!-- 매칭된 컴포넌트가 렌더링되는 위치 -->
<RouterView />
</template>
<style>
/* RouterLink 활성화 스타일 */
.router-link-active {
font-weight: bold;
}
.router-link-exact-active {
color: #42b883;
}
</style>
동적 라우트 매칭
const routes = [
// 동적 세그먼트 — :id
{
path: '/users/:id',
name: 'user-detail',
component: () => import('@/views/UserDetail.vue')
},
// 여러 동적 세그먼트
{
path: '/users/:userId/posts/:postId',
name: 'user-post',
component: () => import('@/views/UserPost.vue')
},
// 선택적 파라미터 — ?
{
path: '/users/:id?',
component: () => import('@/views/UserView.vue')
},
// 정규식 매칭
{
path: '/articles/:id(\\d+)', // 숫자만 매칭
component: () => import('@/views/ArticleView.vue')
},
// Catch-all — 404 페이지
{
path: '/:pathMatch(.*)*',
name: 'not-found',
component: () => import('@/views/NotFound.vue')
}
]
<!-- UserDetail.vue -->
<script setup lang="ts">
import { useRoute } from 'vue-router'
import { watch } from 'vue'
const route = useRoute()
// route.params로 동적 세그먼트 접근
console.log(route.params.id)
// 같은 컴포넌트에서 파라미터만 변경되면 컴포넌트가 재사용됨
// watch로 파라미터 변경을 감시해야 함
watch(
() => route.params.id,
async (newId) => {
// 새 데이터 로드
// await fetchUser(newId)
}
)
</script>
프로그래매틱 네비게이션
<script setup lang="ts">
import { useRouter } from 'vue-router'
const router = useRouter()
// push — 히스토리에 추가
const goToUser = (id: number) => {
router.push(`/users/${id}`)
// 또는 이름 기반
router.push({ name: 'user-detail', params: { id } })
// 쿼리 파라미터
router.push({ path: '/search', query: { q: 'vue', page: 1 } })
}
// replace — 현재 항목을 교체 (뒤로 가기 불가)
const replaceRoute = () => {
router.replace({ name: 'home' })
}
// go — 히스토리 이동
const goBack = () => router.go(-1)
const goForward = () => router.go(1)
</script>
중첩 라우트
const routes = [
{
path: '/dashboard',
component: () => import('@/views/Dashboard.vue'),
children: [
{
path: '', // /dashboard — 기본 자식 라우트
component: () => import('@/views/DashboardHome.vue')
},
{
path: 'analytics', // /dashboard/analytics
component: () => import('@/views/DashboardAnalytics.vue')
},
{
path: 'settings', // /dashboard/settings
component: () => import('@/views/DashboardSettings.vue')
}
]
}
]
<!-- Dashboard.vue -->
<template>
<div class="dashboard">
<aside>
<RouterLink to="/dashboard">홈</RouterLink>
<RouterLink to="/dashboard/analytics">분석</RouterLink>
<RouterLink to="/dashboard/settings">설정</RouterLink>
</aside>
<main>
<!-- 자식 라우트가 여기에 렌더링됨 -->
<RouterView />
</main>
</div>
</template>
History 모드 vs Hash 모드
| 항목 | History 모드 | Hash 모드 |
|---|---|---|
| URL | /about | /#/about |
| API | HTML5 History API | window.location.hash |
| 서버 설정 | 필요 (모든 경로 → index.html) | 불필요 |
| SEO | 유리 | 불리 |
import { createRouter, createWebHistory, createWebHashHistory } from 'vue-router'
// History 모드 (권장)
const router = createRouter({
history: createWebHistory(),
routes
})
// Hash 모드
const router = createRouter({
history: createWebHashHistory(),
routes
})
라우트 메타 필드
const routes = [
{
path: '/admin',
component: AdminLayout,
meta: {
requiresAuth: true,
role: 'admin'
},
children: [/* ... */]
}
]
<script setup lang="ts">
import { useRoute } from 'vue-router'
const route = useRoute()
console.log(route.meta.requiresAuth) // true
</script>
면접 팁
- **History 모드에서 서버 설정이 필요한 이유 **: 브라우저가
/about을 서버에 요청하면 서버에 해당 파일이 없으므로 404를 반환합니다. 모든 경로를index.html로 리다이렉트하는 설정이 필요합니다 - 동적 라우트에서 ** 같은 컴포넌트가 재사용 **되는 것을 이해하고, watch로 파라미터 변경을 감시하는 패턴을 알고 있어야 합니다
- 지연 로딩(
() => import(...))은 ** 코드 분할 **과 ** 초기 로딩 최적화 **의 핵심입니다
요약
Vue Router는 createRouter로 설정하고, RouterView에서 매칭된 컴포넌트를 렌더링합니다. 동적 세그먼트(:id)로 유연한 URL 매칭이 가능하고, 중첩 라우트로 레이아웃을 구성합니다. History 모드 사용 시 서버 설정이 필수이며, 지연 로딩으로 번들을 분할하는 것이 권장됩니다.
댓글 로딩 중...