Перейти к основному контенту
Tech Path Finder
КурсыИнтервьюКод-ревьюБлог
Tech Path Finder

Персонализированный путеводитель в IT. Квизы, мок-интервью, код ревью и аналитика прогресса.

@potapov_me

Платформа

  • Курсы
  • Прогресс
  • Мок-интервью
  • Код ревью
  • Живое ревью с ИИ
  • Тренажёр переговоров
  • Закладки

Контент

  • Блог
  • Главная
  • Обратная связь

Компания

  • О проекте
  • Тарифы
  • Условия использования
  • Конфиденциальность
  • Согласие на обработку данных
  • Cookie
  • Реквизиты

Аккаунт

  • Войти
  • Зарегистрироваться
  • Профиль

© 2026 Tech Path Finder. Все права защищены.

·ИП Потапов К.С.·Политика конфиденциальности·
Сделано с ❤️ в России
  1. Vue Router 4
vue_router

Vue Router 4

Установка и конфигурация роутера, динамические маршруты, навигационные guards, вложенные маршруты, lazy loading

Vue Router 4

Vue Router — официальная библиотека маршрутизации для Vue.js. Версия 4 разработана специально для Vue 3 и полностью интегрирована с Composition API.

#Установка и базовая конфигурация

Vue Router устанавливается как отдельный пакет и регистрируется как плагин в приложении Vue.

Установка через npm:

npm install vue-router@4

Базовая конфигурация создаётся в отдельном файле. Рекомендуется держать конфигурацию роутера отдельно от точки входа:

// src/router/index.js import { createRouter, createWebHistory } from 'vue-router' import HomeView from '@/views/HomeView.vue' import AboutView from '@/views/AboutView.vue' const routes = [ { path: '/', name: 'home', component: HomeView }, { path: '/about', name: 'about', component: AboutView } ] const router = createRouter({ // createWebHistory — HTML5 History API, чистые URL без # history: createWebHistory(import.meta.env.BASE_URL), routes }) export default router

Регистрируем роутер в приложении через app.use():

// src/main.js import { createApp } from 'vue' import App from './App.vue' import router from './router' const app = createApp(App) app.use(router) app.mount('#app')

#createWebHistory vs createWebHashHistory

Vue Router предоставляет несколько режимов истории. Выбор зависит от возможностей сервера.

createWebHistory использует HTML5 History API. URL выглядят чисто: /about, /users/123. Требует настройки сервера — все запросы должны перенаправляться на index.html:

// Чистые URL: http://example.com/about import { createWebHistory } from 'vue-router' const router = createRouter({ history: createWebHistory() })

createWebHashHistory добавляет # в URL: /#/about, /#/users/123. Работает без настройки сервера, так как всё после # не отправляется на сервер. Подходит для статического хостинга:

// URL с хешем: http://example.com/#/about import { createWebHashHistory } from 'vue-router' const router = createRouter({ history: createWebHashHistory() })

createMemoryHistory хранит историю в памяти — используется для SSR и тестов, не изменяет URL браузера.

#RouterView и RouterLink

<RouterView> — точка монтирования: здесь рендерится компонент, соответствующий текущему маршруту. <RouterLink> — замена тега <a>, умеет определять активный маршрут:

<!-- App.vue --> <template> <div id="app"> <nav> <!-- RouterLink не перезагружает страницу, обновляет историю --> <RouterLink to="/">Главная</RouterLink> <RouterLink to="/about">О нас</RouterLink> <!-- С именованным маршрутом --> <RouterLink :to="{ name: 'user', params: { id: 123 } }"> Профиль </RouterLink> <!-- Кастомный активный класс --> <RouterLink to="/admin" active-class="nav-active" exact-active-class="nav-exact-active" > Администрация </RouterLink> </nav> <!-- Компонент текущего маршрута рендерится здесь --> <RouterView /> </div> </template>

Vue Router автоматически добавляет классы router-link-active (когда маршрут активен или является родительским) и router-link-exact-active (точное совпадение). Это удобно для стилизации навигации.

#Динамические сегменты маршрута

Динамические сегменты позволяют создавать маршруты с переменными частями URL, например /users/:id:

// src/router/index.js const routes = [ { path: '/users/:id', name: 'user', component: () => import('@/views/UserView.vue') }, { // Несколько динамических сегментов path: '/posts/:year/:month/:slug', name: 'post', component: () => import('@/views/PostView.vue') }, { // Опциональный параметр path: '/search/:query?', name: 'search', component: () => import('@/views/SearchView.vue') } ]

Доступ к параметрам в компоненте через useRoute():

<!-- UserView.vue --> <template> <div> <div v-if="isLoading">Загрузка...</div> <div v-else-if="user"> <h1>{{ user.name }}</h1> <p>Email: {{ user.email }}</p> </div> </div> </template> <script setup> import { ref, watch } from 'vue' import { useRoute } from 'vue-router' const route = useRoute() const user = ref(null) const isLoading = ref(false) // Загружаем данные при изменении параметра watch( () => route.params.id, async (newId) => { isLoading.value = true const res = await fetch(`/api/users/${newId}`) user.value = await res.json() isLoading.value = false }, { immediate: true } ) </script>

Также можно передавать params как props компонента — это делает компонент независимым от роутера:

// router/index.js { path: '/users/:id', component: UserView, props: true // route.params автоматически становятся props }

#Программная навигация: useRouter

useRouter() предоставляет экземпляр роутера для программной навигации:

<script setup> import { useRouter, useRoute } from 'vue-router' const router = useRouter() const route = useRoute() // Навигация к маршруту — добавляет запись в историю async function login(credentials) { await authApi.login(credentials) // По имени маршрута router.push({ name: 'dashboard' }) } // replace — заменяет текущую запись истории (кнопка «назад» не вернёт) function redirectToLogin() { router.replace({ name: 'login', query: { redirect: route.fullPath } }) } // go() — перемещение по истории function goBack() { router.go(-1) // То же что router.back() } // С параметрами и query function navigateToUser(userId) { router.push({ name: 'user', params: { id: userId }, query: { tab: 'profile' }, hash: '#contacts' }) } </script>

#Query params и hash

Query-параметры и хэш — дополнительные части URL для фильтрации, состояния UI:

<template> <!-- URL: /products?category=electronics&sort=price&page=2 --> <div> <select v-model="category" @change="updateQuery"> <option value="">Все категории</option> <option value="electronics">Электроника</option> <option value="clothing">Одежда</option> </select> <select v-model="sort" @change="updateQuery"> <option value="date">По дате</option> <option value="price">По цене</option> </select> </div> </template> <script setup> import { ref, watch } from 'vue' import { useRoute, useRouter } from 'vue-router' const route = useRoute() const router = useRouter() // Инициализируем из query params const category = ref(route.query.category || '') const sort = ref(route.query.sort || 'date') // Синхронизируем URL с состоянием function updateQuery() { router.push({ query: { category: category.value || undefined, // undefined удаляет параметр sort: sort.value, page: 1 // Сбрасываем пагинацию } }) } // Реагируем на изменение URL (например, кнопка "назад") watch( () => route.query, (newQuery) => { category.value = newQuery.category || '' sort.value = newQuery.sort || 'date' } ) </script>

#Вложенные маршруты

Вложенные маршруты позволяют создавать иерархические интерфейсы с несколькими уровнями <RouterView>:

// router/index.js const routes = [ { path: '/dashboard', component: DashboardLayout, // children будут рендериться внутри RouterView в DashboardLayout children: [ { path: '', // /dashboard name: 'dashboard', component: DashboardHome }, { path: 'analytics', // /dashboard/analytics name: 'dashboard-analytics', component: DashboardAnalytics }, { path: 'settings', // /dashboard/settings component: DashboardSettings, children: [ { path: 'profile', // /dashboard/settings/profile component: SettingsProfile }, { path: 'security', // /dashboard/settings/security component: SettingsSecurity } ] } ] } ]
<!-- DashboardLayout.vue — содержит второй RouterView --> <template> <div class="dashboard"> <aside> <RouterLink :to="{ name: 'dashboard' }">Главная</RouterLink> <RouterLink :to="{ name: 'dashboard-analytics' }">Аналитика</RouterLink> <RouterLink to="/dashboard/settings/profile">Профиль</RouterLink> </aside> <main> <!-- Дочерний компонент рендерится здесь --> <RouterView /> </main> </div> </template>

#Навигационные guards

Guards — это хуки, которые позволяют контролировать навигацию: аутентификация, проверка прав, несохранённые изменения:

// router/index.js — глобальные guards // beforeEach выполняется перед каждым переходом router.beforeEach(async (to, from, next) => { const authStore = useAuthStore() // Маршруты требующие авторизации помечаем meta.requiresAuth if (to.meta.requiresAuth && !authStore.isLoggedIn) { // Сохраняем куда хотел перейти пользователь next({ name: 'login', query: { redirect: to.fullPath } }) return } // Маршруты только для гостей (login/register) if (to.meta.guestOnly && authStore.isLoggedIn) { next({ name: 'dashboard' }) return } // Продолжаем навигацию next() }) // afterEach — выполняется после перехода (нет next) router.afterEach((to, from) => { // Обновляем заголовок страницы document.title = to.meta.title ?? 'My App' // Аналитика analytics.trackPageView(to.path) })

Маршруты с мета-данными:

const routes = [ { path: '/profile', name: 'profile', component: ProfileView, meta: { requiresAuth: true, title: 'Профиль' } }, { path: '/login', name: 'login', component: LoginView, meta: { guestOnly: true, title: 'Вход' } } ]

Внутрикомпонентные guards через Composition API:

<script setup> import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router' import { ref } from 'vue' const hasUnsavedChanges = ref(false) // Вызывается перед уходом с этого компонента onBeforeRouteLeave((to, from, next) => { if (hasUnsavedChanges.value) { const confirmed = window.confirm('У вас есть несохранённые изменения. Покинуть страницу?') next(confirmed) } else { next() } }) // Вызывается когда маршрут меняется, но компонент остаётся (другой параметр) onBeforeRouteUpdate(async (to) => { // Например, переход /users/1 -> /users/2 await loadUser(to.params.id) }) </script>

#Lazy loading компонентов

Ленивая загрузка разделяет бандл на чанки — компоненты загружаются только когда пользователь переходит к соответствующему маршруту:

// Все компоненты загружаются лениво через динамический импорт const routes = [ { path: '/', // Критический путь — можно грузить сразу component: HomeView }, { path: '/admin', // Большой admin-бандл — грузим лениво component: () => import('@/views/AdminView.vue') }, { path: '/charts', // Группировка в именованный чанк component: () => import(/* webpackChunkName: "charts" */ '@/views/ChartsView.vue') } ]

Для Vite (который используется по умолчанию в Vue 3) именование чанков делается иначе:

// Vite: используем rollupOptions в vite.config.js для именования // Или просто используем динамический импорт — Vite сам управляет чанками component: () => import('@/views/AnalyticsView.vue')

#Практический пример: авторизованное приложение

Соберём всё вместе — конфигурация роутера для реального приложения с авторизацией:

// router/index.js import { createRouter, createWebHistory } from 'vue-router' const routes = [ { path: '/', redirect: '/dashboard' }, { path: '/auth', component: () => import('@/layouts/AuthLayout.vue'), meta: { guestOnly: true }, children: [ { path: 'login', name: 'login', component: () => import('@/views/LoginView.vue') }, { path: 'register', name: 'register', component: () => import('@/views/RegisterView.vue') } ] }, { path: '/dashboard', component: () => import('@/layouts/DashboardLayout.vue'), meta: { requiresAuth: true }, children: [ { path: '', name: 'dashboard', component: () => import('@/views/DashboardView.vue') }, { path: 'profile', name: 'profile', component: () => import('@/views/ProfileView.vue') }, { path: 'settings', name: 'settings', component: () => import('@/views/SettingsView.vue') } ] }, { path: '/:pathMatch(.*)*', name: 'not-found', component: () => import('@/views/NotFoundView.vue') } ] const router = createRouter({ history: createWebHistory(), routes, scrollBehavior(to, from, savedPosition) { // Восстанавливаем позицию прокрутки при navigating назад if (savedPosition) return savedPosition if (to.hash) return { el: to.hash, behavior: 'smooth' } return { top: 0 } } }) export default router

Далее: Анимации в Vue 3