логотип PurpleSchool
логотип PurpleSchool

Как организовать страницы и маршруты в проекте на 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/settingsUserProfile + 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).


Как хранить сложную структуру маршрутов

В крупных приложениях удобно разделять маршруты на модули и собирать их из отдельных файлов.

Пример

  1. Внутри папки router создайте отдельные файлы:
src/
|-- router/
|   |-- admin.js
|   |-- user.js
|   `-- index.js
  1. В каждом файле — свой массив маршрутов, например, для админки:
// src/router/admin.js
export default [
  {
    path: '/admin',
    component: () => import('../views/admin/AdminDashboard.vue')
  },
  // другие admin-маршруты
]
  1. В основном файле объединяйте их:
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 } } }) Теперь при каждом переходе страница будет прокручиваться к началу.

Стрелочка влевоИнтеграция Vue с PHP для создания динамичных веб-приложенийNuxt JS и Vue 3 для SSR приложенийСтрелочка вправо

Постройте личный план изучения Vue до уровня Middle — бесплатно!

Vue — часть карты развития Frontend

  • step100+ шагов развития
  • lessons30 бесплатных лекций
  • lessons300 бонусных рублей на счет

Бесплатные лекции

Все гайды по Vue

Руководство по валидации форм во Vue.jsИнтеграция Tiptap для создания редакторов на VueРабота с таблицами во Vue через TanStackИнструкция по установке и компонентам Vue sliderУправление пакетами Vue js с помощью npmУправление пакетами и node modules в Vue проектахКак использовать meta для улучшения SEO на VueПолный гайд по компоненту messages во Vuejs5 правил использования Inertia с Vue и LaravelРабота с модулями и пакетами в VueИнструкция по работе с grid на VueGithub для Vue проектов - подробная инструкция по хранению и совместной работеНастройка ESLint для Vue проектов и поддержка качества кодаОбработка ошибок и отладка в Vue.jsИспользование Vue Devtools для отладки и мониторинга приложенийРабота с конфигурационными файлами и скриптами VueСоздание и настройка проектов Vue с помощью Vue CLI3 способа интеграции Chart.js с Vue для создания графиковРабота с Canvas во VueИнструкция по реализации календаря во VueРабота с Ant Design Vue для создания UI на Vue
Обзор и использование утилит Vue для удобной разработкиРабота с обновлениями компонента и жизненным циклом updateРазрешение конфликтов и ошибок с помощью Vue resolveИспользование query-параметров и их обработка в маршрутах VueЗагрузка и управление состоянием загрузки в VueИспользование библиотек Vue для расширения функционалаРабота с JSON данными в приложениях VueКак работать с экземплярами компонента Instance во VueПолучение данных и API-запросы во Vue.jsЭкспорт и импорт данных и компонентов в VueОбработка событий и их передача между компонентами VuejsГайд по defineEmits на Vue 3Понимание core функционала Vue и его применениеПонимание и применение Composition API в Vue 3Понимание и работа с компилятором VueКогда и как использовать $emit и call во VueВзаимодействие с внешними API через Axios в Vue
Веб приложения на Vue архитектура и лучшие практикиИспользование Vite для быстрого старта и сборки проектов на Vue 3Работа с URL и ссылками в приложениях на VueРабота с пользовательскими интерфейсами и UI библиотеками во VueОрганизация и структура исходных файлов в проектах VueИспользование Quasar Framework для разработки на Vue с готовыми UI-компонентамиОбзор популярных шаблонов и стартовых проектов на VueИнтеграция Vue с PHP для создания динамичных веб-приложенийКак организовать страницы и маршруты в проекте на VueNuxt JS и Vue 3 для SSR приложенийСоздание серверных приложений на Vue с помощью Nuxt jsИспользование Vue Native для разработки мобильных приложенийОрганизация и управление индексной страницей в проектах VueИспользование Docker для контейнеризации приложений на VueИнтеграция Vue.js с Django для создания полноценных веб-приложенийСоздание и работа с дистрибутивом build dist Vue приложенийРабота со стилями и CSS в Vue js для красивых интерфейсовСоздание и структурирование Vue.js приложенияКак исправить ошибку cannot find module vueНастройка и сборка проектов Vue с использованием современных инструментовИнтеграция Vue с Bitrix для корпоративных решенийРазработка административных панелей на Vue js
5 библиотек для создания tree view во VueИнтеграция Tailwind CSS с Vue для современных интерфейсовИнтеграция Vue с серверной частью и HTTPS настройкамиКак обрабатывать async операции с Promise во VueИнтеграция Node.js и Vue.js для разработки приложенийРуководство по интеграции Vue js в NET проектыПримеры использования JSX во VueГайд по импорту и регистрации компонентов на VueМногоязычные приложения на Vue с i18nИнтеграция FLIR данных с Vue5 примеров использования filter во Vue для упрощения разработки3 примера реализации drag-and-drop во Vue
Управление переменными и реактивными свойствами во VueИспользование v for и slot в VueПрименение v-bind для динамической привязки атрибутов в VueУправление пользователями и их данными в Vue приложенияхСоздание и использование UI Kit для Vue приложенийТипизация и использование TypeScript в VuejsИспользование шаблонов в Vue js для построения интерфейсовИспользование Swiper для создания слайдеров в VueРабота со стилями и стилизацией в VueСтруктура и особенности Single File Components SFC в VueРабота со SCSS в проектах на Vue для стилизацииРабота со скроллингом и прокруткой в Vue приложенияхПрименение script setup синтаксиса в Vue 3 для упрощения компонентовИспользование scoped стилей для изоляции CSS в компонентах Vue3 способа улучшить навигацию Vue с push()Обработка запросов и асинхронных операций в VueПонимание и использование provide inject для передачи данных между компонентамиПередача и использование props в Vue 3 для взаимодействия компонентовПередача данных между компонентами с помощью props в Vue jsУправление property и функциями во Vue.jsРабота со свойствами компонентов VueУправление параметрами и динамическими данными во VueРабота с lifecycle-хуком onMounted во VueОсновы работы с объектами в VueПонимание жизненного цикла компонента Vue js на примере mountedИспользование модальных окон modal в Vue приложенияхИспользование методов в компонентах Vue для обработки логикиИспользование метода map в Vue для обработки массивовИспользование хуков жизненного цикла Vue для управления состоянием компонентаРабота с ключами key в списках и компонентах VueОбработка пользовательского ввода в Vue.jsРабота с изображениями и их оптимизация в VueИспользование хуков жизненного цикла в VueОрганизация сеток и гридов для верстки интерфейсов на VueСоздание и управление формами в VueОрганизация файлов и структура проекта Vue.jsКомпоненты Vue создание передача данных события и emitРабота с динамическими компонентами и данными в Vue3 способа манипулирования DOM на VueРуководство по div во VueИспользование директив в Vue и их расширенные возможностиОсновы и применение директив в VueИспользование директив и их особенности на Vue с помощью defineИспользование компонентов datepicker в Vue для выбора датОрганизация циклов и итераций во VueКак работает компиляция Vue CoreСоздание и использование компонентов в Vue JSОбработка кликов и пользовательских событий в VueИспользование классов в Vue для организации кода и компонентовИспользование директивы checked для управления состоянием чекбоксов в VueГайд на checkbox компонент во VueОтображение данных в виде графиков с помощью Vue ChartСоздание и настройка кнопок в VueСоздание и настройка кнопок в Vue приложенияхРабота с lifecycle-хуками beforeCreate и beforeMount во VueИспользование массивов и их обработка в VueИспользование массивов и методов их обработки в Vue
Использование Vuetify для создания современных интерфейсов на VueИспользование transition во VueТестирование компонентов и приложений на VueРабота с teleport для управления DOM во VueПять шагов по настройке SSR в VuejsИспользование Shadcn UI компонентов с Vue для продвинутых интерфейсовИспользование router-link для навигации в Vue RouterКак использовать require в Vue для динамического импорта модулейРабота с динамическим рендерингом и виртуальным DOM на Vue.jsИспользование ref для управления ссылками и реактивностью в Vue 3Использование Vue Pro и его преимущества для профессиональной разработкиРуководство по nextTick для работы с DOMСоздание и использование компонентов с помощью Vue js и CУправление состоянием и реактивностью через inject и provideДинамическое обновление компонентов и данных на VueГлубокое изучение документации Vue и как эффективно её использоватьИспользование Crystal с Vue для разработкиИспользование вычисляемых свойств для динамического отображения данных на Vue jsОптимизация производительности и предупреждения в Vue
Открыть базу знаний

Лучшие курсы по теме

изображение курса

Vue 3 и Pinia

Антон Ларичев
AI-тренажеры
Практика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.9
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

TypeScript с нуля

Антон Ларичев
AI-тренажеры
Практика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Next.js - с нуля

Антон Ларичев
AI-тренажеры
Практика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее

Отправить комментарий