14. Vue Router 4
🗺️ Vue Router 4
Заголовок раздела «🗺️ Vue Router 4»Vue Router — официальный роутер Vue.js. Без него у тебя SPA без навигации — просто одна страница. С ним — полноценное многостраничное приложение с историей браузера, параметрами URL, вложенными маршрутами и ленивой загрузкой. Поехали! 🚀
Установка и настройка
Заголовок раздела «Установка и настройка»npm install vue-router@4import { createRouter, createWebHistory, type RouteRecordRaw } from 'vue-router'import HomeView from '@/views/HomeView.vue'
const routes: RouteRecordRaw[] = [ { path: '/', name: 'home', component: HomeView, }, { path: '/about', name: 'about', // Ленивая загрузка! Чанк создаётся отдельно component: () => import('@/views/AboutView.vue'), }, { path: '/users/:id', name: 'user', component: () => import('@/views/UserView.vue'), }, { // 404 - ловим всё остальное path: '/:pathMatch(.*)*', name: 'not-found', component: () => import('@/views/NotFoundView.vue'), },]
const router = createRouter({ // createWebHistory — чистые URL (требует настройки сервера) // createWebHashHistory — URL с #hash (работает везде) // createMemoryHistory — для SSR и тестов history: createWebHistory(import.meta.env.BASE_URL), routes,})
export default routerimport { createApp } from 'vue'import App from './App.vue'import router from './router'
createApp(App) .use(router) // Регистрируем роутер .mount('#app')RouterView и RouterLink
Заголовок раздела «RouterView и RouterLink»Два главных компонента роутера:
<!-- App.vue — корень приложения --><template> <header> <nav> <!-- RouterLink — умная ссылка с активным классом --> <RouterLink to="/">Главная</RouterLink> <RouterLink to="/about">О нас</RouterLink>
<!-- По имени маршрута --> <RouterLink :to="{ name: 'user', params: { id: 42 } }"> Мой профиль </RouterLink>
<!-- С query параметрами --> <RouterLink :to="{ path: '/search', query: { q: 'vue' } }"> Поиск </RouterLink> </nav> </header>
<!-- Здесь отображается текущий маршрут --> <RouterView /></template>Стилизация активных ссылок
Заголовок раздела «Стилизация активных ссылок»Vue Router автоматически добавляет классы активным ссылкам:
<style>/* router-link-active — ссылка частично совпадает с URL */.router-link-active { color: #42b883;}
/* router-link-exact-active — точное совпадение */.router-link-exact-active { font-weight: bold; border-bottom: 2px solid #42b883;}</style><!-- Кастомные классы активности --><RouterLink to="/about" active-class="my-active" exact-active-class="my-exact-active"> О нас</RouterLink>Route Params и Query
Заголовок раздела «Route Params и Query»Параметры маршрута (:param)
Заголовок раздела «Параметры маршрута (:param)»// Роут с параметром{ path: '/users/:id', component: UserView }{ path: '/posts/:category/:slug', component: PostView }
// Опциональный параметр{ path: '/users/:id?', component: UserView }
// Regex в параметре (только числа){ path: '/users/:id(\\d+)', component: UserView }<script setup lang="ts">import { useRoute } from 'vue-router'import { computed } from 'vue'
const route = useRoute()
// route.params — текущие параметры маршрутаconst userId = computed(() => Number(route.params.id))const category = computed(() => route.params.category as string)</script>
<template> <h1>Пользователь #{{ userId }}</h1></template>Props вместо route.params (рекомендуется!)
Заголовок раздела «Props вместо route.params (рекомендуется!)»{ path: '/users/:id', component: UserView, props: true, // route.params передаются как props!}<!-- UserView.vue — чище и тестируемее! --><script setup lang="ts">// Просто пропс — компонент не знает о роутереconst props = defineProps<{ id: string}>()</script>Query параметры (?key=value)
Заголовок раздела «Query параметры (?key=value)»<script setup lang="ts">import { useRoute, useRouter } from 'vue-router'import { computed } from 'vue'
const route = useRoute()const router = useRouter()
// Чтение query параметровconst search = computed(() => route.query.q as string || '')const page = computed(() => Number(route.query.page) || 1)
// Обновление query без перезагрузки страницыfunction updateSearch(value: string) { router.push({ query: { ...route.query, // Сохраняем остальные параметры q: value, page: 1, // Сбрасываем страницу при поиске } })}</script>Программная навигация с useRouter
Заголовок раздела «Программная навигация с useRouter»<script setup lang="ts">import { useRouter, useRoute } from 'vue-router'
const router = useRouter()const route = useRoute()
// push — добавляет запись в историю (можно вернуться)function goToHome() { router.push('/')}
function goToUser(id: number) { router.push({ name: 'user', params: { id } })}
// replace — заменяет текущую запись (нельзя вернуться)function redirectToLogin() { router.replace({ name: 'login' })}
// go — навигация по историиfunction goBack() { router.go(-1) // Назад}
function goForward() { router.go(1) // Вперёд}
// push возвращает Promise!async function saveAndGo() { await saveData() await router.push({ name: 'dashboard' }) console.log('Навигация завершена')}</script>Nested Routes — вложенные маршруты
Заголовок раздела «Nested Routes — вложенные маршруты»const routes = [ { path: '/users', component: UsersLayout, // Содержит <RouterView> children: [ { path: '', // /users name: 'users-list', component: UsersList, }, { path: ':id', // /users/42 name: 'user-detail', component: UserDetail, children: [ { path: 'posts', // /users/42/posts component: UserPosts, }, { path: 'settings', // /users/42/settings component: UserSettings, }, ], }, ], },]<!-- UsersLayout.vue — содержит RouterView для дочерних маршрутов --><template> <div class="users-layout"> <aside> <RouterLink to="/users">Все пользователи</RouterLink> </aside> <main> <!-- Здесь отображаются дочерние маршруты --> <RouterView /> </main> </div></template>Named Routes
Заголовок раздела «Named Routes»Всегда используй именованные маршруты вместо строк — это безопаснее при изменении путей:
// В роутере{ path: '/users/:id/edit', name: 'user-edit', component: UserEdit }<!-- В шаблоне --><!-- ❌ Хрупко — если изменишь path, всё сломается --><RouterLink to="/users/42/edit">Редактировать</RouterLink>
<!-- ✅ Надёжно — работает независимо от path --><RouterLink :to="{ name: 'user-edit', params: { id: 42 } }"> Редактировать</RouterLink>useLink — кастомные ссылки
Заголовок раздела «useLink — кастомные ссылки»<script setup lang="ts">import { RouterLink, useLink } from 'vue-router'
const props = defineProps({ ...RouterLink.props,})
const { route, href, isActive, isExactActive, navigate } = useLink(props)</script>
<template> <a :href="href" :class="{ 'is-active': isActive, 'is-exact': isExactActive }" @click.prevent="navigate" > <slot /> </a></template>Шпаргалка
Заголовок раздела «Шпаргалка»// Создание роутераcreateRouter({ history: createWebHistory(), routes })
// В компонентеconst router = useRouter() // Методы навигацииconst route = useRoute() // Текущий маршрут (readonly)
// Навигацияrouter.push('/path')router.push({ name: 'route-name', params: {}, query: {} })router.replace({ name: 'login' })router.go(-1)
// Информация о маршрутеroute.path // '/users/42'route.params // { id: '42' }route.query // { search: 'vue' }route.name // 'user'route.meta // { requiresAuth: true }route.fullPath // '/users/42?search=vue'