В одностраничных приложениях (SPA) маршрутизация происходит без
полной перезагрузки страницы. Это означает, что стандартные мета-теги
(<title>,
<meta name="description">,
<meta property="og:*">) остаются неизменными, если не
обновлять их вручную. Библиотека Navigo предоставляет удобный механизм
для обработки маршрутов, но управление meta-данными ложится на
разработчика.
Динамическое обновление meta необходимо для:
Создание маршрутизатора:
import Navigo from 'navigo';
const router = new Navigo('/', { hash: true });
router
.on('/home', () => renderPage('home'))
.on('/about', () => renderPage('about'))
.resolve();
Функция renderPage отвечает за отрисовку контента.
Именно здесь удобно интегрировать обновление meta-данных.
Самый простой элемент — <title>. Обновляется
напрямую через DOM:
function updateTitle(title) {
document.title = title;
}
Использование в маршрутах:
router.on('/about', () => {
renderPage('about');
updateTitle('О компании');
});
Meta description влияет на сниппеты в поисковой выдаче:
function updateDescription(description) {
let tag = document.querySelector('meta[name="description"]');
if (!tag) {
tag = document.createElement('meta');
tag.setAttribute('name', 'description');
document.head.appendChild(tag);
}
tag.setAttribute('content', description);
}
Применение:
router.on('/home', () => {
renderPage('home');
updateDescription('Главная страница сайта');
});
Для социальных сетей важны теги og:title,
og:description, og:image:
function updateMetaProperty(property, content) {
let tag = document.querySelector(`meta[property="${property}"]`);
if (!tag) {
tag = document.createElement('meta');
tag.setAttribute('property', property);
document.head.appendChild(tag);
}
tag.setAttribute('content', content);
}
Использование:
router.on('/post/:id', ({ data }) => {
const post = getPost(data.id);
renderPost(post);
updateMetaProperty('og:title', post.title);
updateMetaProperty('og:description', post.summary);
updateMetaProperty('og:image', post.image);
});
Для упрощения поддержки удобно создать единый слой управления:
function updateMeta(meta) {
if (meta.title) {
document.title = meta.title;
}
if (meta.description) {
updateDescription(meta.description);
}
if (meta.og) {
Object.entries(meta.og).forEach(([key, value]) => {
updateMetaProperty(`og:${key}`, value);
});
}
}
Маршруты становятся чище:
router.on('/about', () => {
renderPage('about');
updateMeta({
title: 'О компании',
description: 'Информация о компании',
og: {
title: 'О компании',
description: 'Узнайте больше о нас',
image: '/images/about.jpg'
}
});
});
Navigo поддерживает хуки, которые позволяют выполнять код перед обработкой маршрута.
router.hooks({
before: (done, match) => {
const routeMeta = getRouteMeta(match.url);
if (routeMeta) {
updateMeta(routeMeta);
}
done();
}
});
Функция getRouteMeta может возвращать заранее описанные
meta-данные:
const metaConfig = {
'/home': {
title: 'Главная',
description: 'Добро пожаловать'
},
'/about': {
title: 'О нас',
description: 'Информация о компании'
}
};
function getRouteMeta(url) {
return metaConfig[url];
}
Для маршрутов с параметрами требуется генерация данных:
router.on('/product/:id', ({ data }) => {
const product = getProduct(data.id);
renderProduct(product);
updateMeta({
title: product.name,
description: product.description,
og: {
title: product.name,
description: product.description,
image: product.image
}
});
});
Если meta зависит от API, важно обновлять их после загрузки:
router.on('/article/:id', async ({ data }) => {
const article = await fetchArticle(data.id);
renderArticle(article);
updateMeta({
title: article.title,
description: article.excerpt
});
});
При частом обновлении важно избегать дублирования тегов:
meta с разными значениямиproperty и
nameSPA-приложения часто используют:
В таких случаях:
Важно не конфликтовать с серверной разметкой:
// не создавать новый тег, если он уже есть
document.querySelector('meta[name="description"]');
Отсутствие обновления title
Дублирование meta-тегов
<meta name="description">Игнорирование Open Graph
Синхронное обновление при асинхронных данных
Дополнительные возможности:
Пример шаблона:
function generateMeta(template, data) {
return template.replace(/\{\{(.*?)\}\}/g, (_, key) => data[key.trim()]);
}
Рекомендуется выделить отдельный модуль:
/meta
├── updateMeta.js
├── metaConfig.js
└── helpers.js
Это позволяет:
Чёткое соблюдение этой последовательности исключает рассинхронизацию между содержимым страницы и её мета-данными.