Управление заголовками страниц

В современных веб-приложениях заголовки страниц играют важную роль для удобства пользователя и SEO. В Vue Router существует несколько подходов для динамического изменения заголовка страницы при навигации между маршрутами.


Определение заголовка в маршрутах

Vue Router позволяет добавлять произвольные метаданные к маршрутам с помощью свойства meta. Для заголовка страницы используется поле title:

import { createRouter, createWebHistory } from 'vue-router'
import Home from './views/Home.vue'
import About from './views/About.vue'

const routes = [
  {
    path: '/',
    component: Home,
    meta: { title: 'Главная' }
  },
  {
    path: '/about',
    component: About,
    meta: { title: 'О проекте' }
  }
]

const router = createRouter({
  history: createWebHistory(),
  routes
})

export default router

Ключевой момент: любое поле meta доступно через объект маршрута to.meta в хуках навигации.


Изменение заголовка с использованием глобального хука afterEach

Самый распространённый способ обновления заголовка — это глобальный навигационный хук afterEach:

router.afterEach((to) => {
  document.title = to.meta.title || 'Default Title'
})
  • to.meta.title — заголовок, заданный в маршруте.
  • Если заголовок не указан, устанавливается значение по умолчанию.

Этот метод гарантирует, что заголовок страницы всегда синхронизирован с текущим маршрутом.


Динамические заголовки с параметрами маршрута

Если заголовок должен зависеть от параметров маршрута, можно использовать функцию для генерации строки:

const routes = [
  {
    path: '/user/:id',
    component: UserProfile,
    meta: {
      title: route => `Профиль пользователя ${route.params.id}`
    }
  }
]

router.afterEach((to) => {
  const title = typeof to.meta.title === 'function'
    ? to.meta.title(to)
    : to.meta.title
  document.title = title || 'Default Title'
})

Особенности такого подхода:

  • meta.title может быть строкой или функцией, принимающей объект маршрута to.
  • Позволяет строить заголовки динамически, например, с подстановкой имени пользователя или статьи.

Асинхронные данные и заголовок страницы

Если заголовок зависит от данных, получаемых асинхронно (например, из API), рекомендуется использовать beforeResolve:

router.beforeResolve(async (to, from, next) => {
  if (to.meta.asyncTitle) {
    const data = await fetchTitle(to.params.id)
    document.title = data
  } else {
    document.title = to.meta.title || 'Default Title'
  }
  next()
})
  • beforeResolve вызывается перед завершением навигации, но после разрешения всех асинхронных компонентов.
  • Обеспечивает, что заголовок будет установлен корректно даже при загрузке данных из сервера.

Многоуровневая структура маршрутов и заголовки

Вложенные маршруты могут иметь собственные метаданные. Для построения заголовка с учётом иерархии используют цепочку matched:

router.afterEach((to) => {
  const nearestWithTitle = to.matched.slice().reverse().find(r => r.meta && r.meta.title)
  if (nearestWithTitle) {
    document.title = nearestWithTitle.meta.title
  } else {
    document.title = 'Default Title'
  }
})
  • to.matched — массив маршрутов от родителя к дочернему.
  • Использование slice().reverse() позволяет приоритетно брать заголовок из самого конкретного (дочернего) маршрута.

Интеграция с компонентами

Можно обновлять заголовок внутри компонентов через watch маршрута:

export default {
  watch: {
    $route(to) {
      document.title = to.meta.title || 'Default Title'
    }
  },
  mounted() {
    document.title = this.$route.meta.title || 'Default Title'
  }
}
  • Подходит для случаев, когда заголовок зависит от состояния компонента или его данных.
  • Менее предпочтительно для глобальной навигации, но полезно при сложной логике внутри конкретных страниц.

Важные рекомендации

  • Заголовок должен всегда иметь значение по умолчанию, чтобы избежать пустого <title>.
  • Для SEO важно, чтобы заголовок отражал контент страницы, особенно для страниц с динамическим содержимым.
  • Использование глобальных хуков упрощает поддержку проекта, избегая дублирования логики в компонентах.

Управление заголовками в Vue Router становится гибким благодаря комбинации meta, глобальных хуков и функций. Это позволяет создавать как простые статические заголовки, так и динамические, зависящие от параметров маршрута или асинхронных данных.