Дмитрий Кузнецов
Как организовать страницы и маршруты в проекте на Vue
Введение
В приложениях на Vue одна из ключевых задач — грамотно организовать страницы и маршруты. Без четкой структуры и понятной маршрутизации ваш проект быстро превратится в запутанную систему, где сложно добавить новую страницу или поддерживать существующие. Vue предоставляет мощный инструмент для решения этой задачи — библиотеку Vue Router.
В этой статье я расскажу вам, как спланировать архитектуру страниц, правильно организовать файлы и директории, настроить роутинг для различных сценариев, реализовать вложенные маршруты и ленивую загрузку компонентов. Мы рассмотрим практические примеры и лучшие подходы, чтобы сэкономить ваше время и сделать приложение удобным для поддержки и расширения.
Что такое маршруты и почему их организация важна
Маршруты (routes) позволяют пользователю перемещаться по разным страницам без полного перезагрузки приложения. Каждый маршрут ассоциируется с определённым компонентом Vue, который рендерится при переходе на соответствующий URL.
Правильная организация маршрутов облегчает:
- Разделение кода на логические части
- Повторное использование компонентов
- Обеспечение масштабируемости (легко добавлять новые страницы)
- Поддержку читаемого и поддерживаемого кода
Если игнорировать эти принципы на старте, ваше приложение станет сложным в поддержке по мере роста.
Установка и базовая настройка Vue Router
Давайте начнем с установки Vue Router в стандартный проект на Vue 3.
npm install vue-router@4
После установки, импортируйте и настройте роутер. Пример для проекта, созданного через Vue CLI:
// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
const routes = [
{
path: '/', // URL адрес
name: 'Home', // Имя маршрута
component: Home // Компонент, который отобразится
},
// Добавляйте другие маршруты здесь
]
const router = createRouter({
history: createWebHistory(process.env.BASE_URL), // Используем HTML5 history API
routes
})
export default router
Теперь добавьте роутер в приложение:
// src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
createApp(App)
.use(router) // Подключаем роутер к приложению
.mount('#app')
Структура директорий для страниц и компонентов
Обычно для организации страниц и связанных с ними компонентов используются специальные директории.
Очень популярный подход — выносить компоненты-страницы в папку views
, а повторно используемые компоненты — в папку components
.
src/
|-- components/
| |-- Header.vue
| |-- Footer.vue
| `-- ...
|-- views/
| |-- Home.vue
| |-- About.vue
| |-- UserProfile.vue
| `-- ...
|-- router/
| `-- index.js
|-- App.vue
`-- main.js
- components/ — для переиспользуемых частей интерфейса.
- views/ — для компонентов, соответствующих отдельным страницам/маршрутам.
Почему делят именно так?
Компоненты страниц (views
) зачастую "тяжелее", отвечают за работу с данными и содержат подсоставляющие (children) — мелкие компоненты, вынесенные в общую папку.
Создание и описание маршрутов
Добавление страниц (views) и их маршрутов
Допустим, у вас есть три страницы: Главная (Home), О нас (About) и Профиль пользователя (UserProfile).
Создайте для каждой страницы отдельный .vue
-файл в папке views
:
views/Home.vue
views/About.vue
views/UserProfile.vue
А теперь добавьте маршруты в конфигурацию:
// src/router/index.js
import Home from '../views/Home.vue'
import About from '../views/About.vue'
import UserProfile from '../views/UserProfile.vue'
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: About
},
{
path: '/user/:id', // :id — динамический сегмент
name: 'UserProfile',
component: UserProfile,
props: true // Позволяет передавать id как пропс в компонент
}
]
Как работает динамический маршрут
Cегмент с двоеточием (:id
) позволяет принимать любой параметр в этом месте URL.
// Допустим URL: /user/42
// В компонент UserProfile попадет prop id = "42"
внутри компонента вы можете получить его как пропс или же через объект маршрута:export default {
props: ['id']
// Теперь id доступен как this.id
}
или
js
import { useRoute } from 'vue-router'
const route = useRoute()
console.log(route.params.id) // Выведет id из URL
Организация вложенных маршрутов (Nested Routes)
Часто требуется, чтобы компонент-страница содержал области для отображения дочерних компонентов в разных состояниях (например, профиль пользователя и вкладки: информация, настройки, безопасность).
Вот пример вложенных маршрутов:
import UserProfile from '../views/UserProfile.vue'
import UserInfo from '../components/UserInfo.vue'
import UserSettings from '../components/UserSettings.vue'
const routes = [
{
path: '/user/:id',
component: UserProfile,
children: [
{
path: '', // по умолчанию
component: UserInfo
},
{
path: 'settings',
component: UserSettings
}
]
}
]
В компоненте UserProfile.vue
вы должны разместить тег <router-view />
:
<template>
<div>
<h1>Профиль пользователя</h1>
<!-- Здесь будет отображаться вложенный маршрут -->
<router-view/>
</div>
</template>
Теперь, если вы зайдете на /user/42
, отрисуется UserProfile
+ UserInfo
. Если перейдете на /user/42/settings
— UserProfile
+ UserSettings
.
Ленивые загрузки (Lazy Loading) страниц
Когда приложение становится крупным, все страницы сразу включать в бандл неразумно — это увеличит время загрузки приложения. Vue Router поддерживает ленивую (асинхронную) подгрузку компонентов.
Пример ленивой загрузки компонента:
const About = () => import('../views/About.vue')
Добавьте такой маршрут:
const routes = [
{
path: '/about',
name: 'About',
component: () => import('../views/About.vue')
}
]
В этом случае код компонента About будет подгружаться только тогда, когда пользователь первый раз перейдёт на /about.
Программная навигация
Вы можете программно перенаправить пользователя на другой маршрут через методы роутера:
// Получаем доступ к экземпляру роутера
import { useRouter } from 'vue-router'
export default {
setup() {
const router = useRouter()
const goToAbout = () => {
router.push({ name: 'About' }) // Переход по имени маршрута
}
return { goToAbout }
}
}
Вызывайте функцию goToAbout
из обработчика событий (например, по клику на кнопку).
Использование имени маршрута и параметров
Переходить по маршрутам можно не только по адресу (path
), но и по имени (name
). Это удобно, если путь может измениться, а имя — остается постоянным.
Пример:
router.push({ name: 'UserProfile', params: { id: 42 } })
// Перейдет на /user/42
Работа с несколькими областями (Named Views)
Иногда на одной странице нужно отрисовать несколько компонентов в зависимости от маршрута (например, sidebar и main content). Для этого используют именованные вьюхи.
Настройка именованных областей и маршрута
const routes = [
{
path: '/dashboard',
components: {
default: () => import('../views/DashboardMain.vue'), // основной <router-view>
sidebar: () => import('../components/DashboardSidebar.vue') // <router-view name="sidebar"/>
}
}
]
А теперь добавьте несколько <router-view>
с разными атрибутами name
:
<template>
<div>
<router-view/> <!-- по умолчанию отрисует DashboardMain.vue -->
<router-view name="sidebar"/> <!-- отрисует DashboardSidebar.vue -->
</div>
</template>
Ограничение доступа с помощью навигационных гардов (Navigation Guards)
Навигационные гарды позволяют внедрять проверку условий при попытке перехода на страницу (например, требовать авторизации).
Пример глобального navigation guard:
// src/router/index.js
router.beforeEach((to, from, next) => {
// Проверяем, требуется ли страница авторизации
if (to.meta.requiresAuth && !isLoggedIn()) {
// Перенаправим на страницу логина
next({ name: 'Login' })
} else {
next() // Разрешить переход
}
})
Чтобы подключить метаданные к маршруту:
{
path: '/secure',
component: SecurePage,
meta: { requiresAuth: true }
}
isLoggedIn()
— это функция, возвращающая признак аутентификации пользователя.
Как создавать навигационное меню
Часто для организации переходов между страницами на сайте используют компонент <router-link>
:
<template>
<nav>
<router-link to="/">Главная</router-link>
<router-link to="/about">О нас</router-link>
<router-link :to="{ name: 'UserProfile', params: { id: 42 } }">Профиль</router-link>
</nav>
</template>
<router-link>
удобен тем, что не перезагружает страницу и автоматически помечает текущую ссылку как активную (css-класс router-link-active
).
Как хранить сложную структуру маршрутов
В крупных приложениях удобно разделять маршруты на модули и собирать их из отдельных файлов.
Пример
- Внутри папки
router
создайте отдельные файлы:
src/
|-- router/
| |-- admin.js
| |-- user.js
| `-- index.js
- В каждом файле — свой массив маршрутов, например, для админки:
// src/router/admin.js
export default [
{
path: '/admin',
component: () => import('../views/admin/AdminDashboard.vue')
},
// другие admin-маршруты
]
- В основном файле объединяйте их:
import adminRoutes from './admin'
import userRoutes from './user'
const routes = [
...adminRoutes,
...userRoutes,
// другие маршруты
]
Обработка несуществующих маршрутов (404)
Чтобы ловить запросы на несуществующие страницы, добавьте маршрут "catch-all":
import NotFound from '../views/NotFound.vue'
const routes = [
// …ваши маршруты
{
path: '/:catchAll(.*)', // Ловит любой путь, какой не был ранее объявлен
name: 'NotFound',
component: NotFound
}
]
Теперь любые неправильные URL приведут к компоненту NotFound.vue.
Использование маршрутов с query-параметрами
Query-параметры добавляют в URL часть после знака "?". Их удобно использовать для фильтрации, поиска и других задач.
Пример перехода с query:
router.push({ path: '/products', query: { sort: 'asc' } })
// Получится /products?sort=asc
Внутри компонента можно получить доступ к query через:
import { useRoute } from 'vue-router'
const route = useRoute()
console.log(route.query.sort) // 'asc'
Заключение
Организация страниц и маршрутов в Vue-проекте — важный этап, который во многом определяет, насколько удобно будет развивать, поддерживать и масштабировать приложение. Vue Router предлагает гибкие возможности для настройки маршрутизации, поддерживает вложенные маршруты, ленивую загрузку, именованные области, query-параметры и прочие фишки, которые пригодятся проектам любого масштаба.
Потратьте время на продуманную структуру с самого начала — это значительно упростит работу над проектом в будущем.
Частозадаваемые технические вопросы по теме статьи и ответы на них
Как реализовать редирект на страницу по умолчанию при заходе на корень сайта?
Добавьте маршрут с атрибутом redirect
:
js
{
path: '/',
redirect: '/home' // перенаправит на /home
}
Как динамически менять заголовок страницы (тега <title>
) при смене маршрута?
Можно использовать навигационный guard и document.title:
js
router.afterEach((to) => {
document.title = to.meta.title || 'Название по умолчанию'
})
Укажите meta: { title: 'Заголовок' }
в описании маршрута.
Почему не работает переход по маршруту, если меняются только query-параметры?
Vue Router не вызывает хук created/mounted при изменении только query. Ориентируйтесь на хук watch
за $route
или используйте хук beforeRouteUpdate
во Vue компоненте:
js
watch: {
'$route.query'(newQuery, oldQuery) {
// Реакция на смену query-параметров
}
}
Как сделать layout (общий шаблон) для части страниц?
Создайте компонент-Layout, в нем — <router-view />
, а нужным маршрутам указывайте этот Layout в качестве компонента:
js
{
path: '/admin',
component: AdminLayout,
children: [
{ path: 'users', component: AdminUsers }
]
}
В этом примере все admin-маршруты будут с общим layout.
Как сбросить scroll к началу страницы при переходе по маршруту?
В объекте настроек роутера укажите scrollBehavior:
js
const router = createRouter({
// ... остальные параметры
scrollBehavior() {
return { left: 0, top: 0 }
}
})
Теперь при каждом переходе страница будет прокручиваться к началу.