SEO и Meta
Управление тегами в <head> в Nuxt построено на Unhead.
Он задаёт разумные значения по умолчанию, даёт несколько мощных композаблов и множество опций для настройки <head> и SEO-метатегов приложения.
Конфигурация Nuxt
В nuxt.config.ts через app.head можно статически задать <head> для всего приложения.
useHead() в app.vue.Имеет смысл задавать здесь то, что редко меняется: заголовок сайта по умолчанию, lang и favicon.
export default defineNuxtConfig({
app: {
head: {
title: 'Nuxt', // default fallback title
htmlAttrs: {
lang: 'en',
},
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
],
},
},
})
Ниже в разделе «Типы» перечислены и другие допустимые поля.
Теги по умолчанию
Nuxt по умолчанию добавляет теги, чтобы сайт корректно отображался сразу:
viewport:width=device-width, initial-scale=1charset:utf-8
Большинству сайтов не нужно менять эти значения по умолчанию; при необходимости их можно обновить через сокращённые поля charset и viewport.
export default defineNuxtConfig({
app: {
head: {
// update Nuxt defaults
charset: 'utf-16',
viewport: 'width=device-width, initial-scale=1, maximum-scale=1',
},
},
})
useHead
Композабл useHead принимает реактивные значения и позволяет управлять <head> из кода.
<script setup lang="ts">
useHead({
title: 'My App',
meta: [
{ name: 'description', content: 'My amazing site.' },
],
bodyAttrs: {
class: 'test',
},
script: [{ innerHTML: 'console.log(\'Hello world\')' }],
})
</script>
Мы рекомендуем композаблы useHead и useHeadSafe.
useSeoMeta
useSeoMeta задаёт SEO-метатеги одним объектом с полной типобезопасностью.
Так проще не ошибиться в атрибутах — например, не перепутать name и property.
<script setup lang="ts">
useSeoMeta({
title: 'My Amazing Site',
ogTitle: 'My Amazing Site',
description: 'This is my amazing site, let me tell you all about it.',
ogDescription: 'This is my amazing site, let me tell you all about it.',
ogImage: 'https://example.com/image.png',
twitterCard: 'summary_large_image',
})
</script>
Компоненты
Во всех сценариях предпочтительнее useHead, но при желании метатеги можно описать в шаблоне компонентами.
Nuxt предоставляет <Title>, <Base>, <NoScript>, <Style>, <Meta>, <Link>, <Body>, <Html> и <Head> для работы с <head> из разметки. Имена этих компонентов должны начинаться с заглавной буквы — так они не пересекаются с обычными HTML-тегами.
<Head> и <Body> могут принимать вложенные мета-теги (из эстетических соображений), но это не влияет на то, где именно вложенные мета-теги будут отображаться в конечном HTML.
<script setup lang="ts">
const title = ref('Hello World')
</script>
<template>
<div>
<Head>
<Title>{{ title }}</Title>
<Meta
name="description"
:content="title"
/>
<Style>
body { background-color: green; }
</Style>
</Head>
<h1>{{ title }}</h1>
</div>
</template>
Удобнее оборачивать теги в <Head> или <Html> — так дедупликация работает предсказуемее.
key на компоненте <Head>.Типы
Ниже приведены нереактивные типы, используемые для useHead, app.head и компонентов.
interface MetaObject {
title?: string
titleTemplate?: string | ((title?: string) => string)
templateParams?: Record<string, string | Record<string, string>>
base?: Base
link?: Link[]
meta?: Meta[]
style?: Style[]
script?: Script[]
noscript?: Noscript[]
htmlAttrs?: HtmlAttributes
bodyAttrs?: BodyAttributes
}
Более подробную информацию о типах см. в @unhead/vue.
Возможности
Реактивность
Реактивность поддерживается для всех свойств путем предоставления вычисляемого значения (computed), геттера или реактивного объекта.
<script setup lang="ts">
const description = ref('My amazing site.')
useHead({
meta: [
{ name: 'description', content: description },
],
})
</script>
<script setup lang="ts">
const description = ref('My amazing site.')
useSeoMeta({
description,
})
</script>
<script setup lang="ts">
const description = ref('My amazing site.')
</script>
<template>
<div>
<Meta
name="description"
:content="description"
/>
</div>
</template>
Шаблон названия
Опция titleTemplate задаёт шаблон заголовка сайта — например, суффикс с названием проекта на каждой странице.
Это может быть строка с %s вместо заголовка страницы или функция.
Функцию нельзя задать в nuxt.config; для полного контроля указывайте titleTemplate в app.vue — тогда шаблон действует на все страницы:
<script setup lang="ts">
useHead({
titleTemplate: (titleChunk) => {
return titleChunk ? `${titleChunk} - Site Title` : 'Site Title'
},
})
</script>
Если на другой странице через useHead задать заголовок Моя страница, на вкладке будет «Моя страница - Заголовок сайта». Передав null, получите только «Заголовок сайта».
Параметры шаблона (templateParams)
Через templateParams можно задать свои плейсхолдеры в titleTemplate помимо стандартного %s и собирать заголовок гибче.
<script setup lang="ts">
useHead({
titleTemplate: (titleChunk) => {
return titleChunk ? `${titleChunk} %separator %siteName` : '%siteName'
},
templateParams: {
siteName: 'Site Title',
separator: '-',
},
})
</script>
Теги body
Вы можете использовать опцию tagPosition: 'bodyClose' для соответствующих тегов, чтобы добавить их в конец тега <body>.
Например:
<script setup lang="ts">
useHead({
script: [
{
src: 'https://third-party-script.com',
// valid options are: 'head' | 'bodyClose' | 'bodyOpen'
tagPosition: 'bodyClose',
},
],
})
</script>
Примеры
Используя definePageMeta
В каталоге pages/ можно сочетать definePageMeta с useHead, чтобы задавать метаданные с учётом маршрута.
Сначала задаём заголовок страницы (макрос обрабатывается на этапе сборки, значение не бывает динамическим):
<script setup lang="ts">
definePageMeta({
title: 'Some Page',
})
</script>
В лейауте можно прочитать метаданные маршрута, заданные на странице:
<script setup lang="ts">
const route = useRoute()
useHead({
meta: [{ property: 'og:title', content: `App Name - ${route.meta.title}` }],
})
</script>
Динамический заголовок (title)
В примере ниже titleTemplate задается либо как строка с заполнителем %s, либо как функция, что позволяет более гибко устанавливать заголовок страницы динамически для каждого маршрута вашего приложения Nuxt:
<script setup lang="ts">
useHead({
// as a string,
// where `%s` is replaced with the title
titleTemplate: '%s - Site Title',
})
</script>
<script setup lang="ts">
useHead({
// or as a function
titleTemplate: (productCategory) => {
return productCategory
? `${productCategory} - Site Title`
: 'Site Title'
},
})
</script>
nuxt.config также используется в качестве альтернативного способа установки заголовка страницы. Однако nuxt.config не позволяет сделать заголовок страницы динамическим. Поэтому рекомендуется использовать titleTemplate в файле app.vue для добавления динамического заголовка, который затем применяется ко всем маршрутам вашего приложения Nuxt.
Внешний CSS
В примере ниже показано, как можно включить Google Fonts, используя свойство link композабла useHead или компонент <Link>:
<script setup lang="ts">
useHead({
link: [
{
rel: 'preconnect',
href: 'https://fonts.googleapis.com',
},
{
rel: 'stylesheet',
href: 'https://fonts.googleapis.com/css2?family=Roboto&display=swap',
crossorigin: '',
},
],
})
</script>
<template>
<div>
<Link
rel="preconnect"
href="https://fonts.googleapis.com"
/>
<Link
rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Roboto&display=swap"
crossorigin=""
/>
</div>
</template>