SEO 与 Meta 标签
Nuxt 底层的 head 管理由 Unhead 提供。你可以得到响应式的 composable、类型安全的 SEO 工具,以及内置组件 —— 按团队习惯任选风格。
nuxt.config.ts —— 全局默认值
放一些不会随页面变化的标签:
export default defineNuxtConfig({
app: {
head: {
titleTemplate: '%s · Nuxt 小册',
htmlAttrs: { lang: 'zh-CN' },
link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }],
},
},
})
Nuxt 还会自动注入:
<meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
useHead —— 响应式 composable
<script setup lang="ts">
const title = ref('Hello World')
useHead({
title,
meta: [{ name: 'description', content: '我的超棒网站。' }],
bodyAttrs: { class: 'app' },
script: [{ innerHTML: 'console.log("loaded")' }],
})
</script>
useHead 支持响应式值,多处调用也会自动去重。
useSeoMeta —— 类型安全的 SEO
useSeoMeta 知道 name 和 property 的区别,拼错、写错一眼就被类型系统发现:
<script setup lang="ts">
useSeoMeta({
title: '我的超棒网站',
description: '这个网站做了啥,来了解一下。',
ogTitle: '我的超棒网站',
ogDescription: '这个网站做了啥,来了解一下。',
ogImage: 'https://example.com/og.png',
twitterCard: 'summary_large_image',
})
</script>
做 SEO 时基本就用它。
组件式写法
喜欢声明式模板也可以:
<script setup lang="ts">
const title = ref('Hello World')
</script>
<template>
<Head>
<Title>{{ title }}</Title>
<Meta name="description" :content="title" />
</Head>
</template>
支持的标签:<Title>、<Meta>、<Link>、<Script>、<Style>、<Base>、<NoScript>、<Html>、<Body>。
Title template
全站标题一般是 “页面 — 站点名” 的模式:
<!-- app.vue -->
<script setup lang="ts">
useHead({
titleTemplate: (title) => title ? `${title} · 我的站点` : '我的站点',
})
</script>
之后任何页面调用 useHead({ title: 'Blog' }) 就会显示成 Blog · 我的站点。
Template params
需要多个占位符?
<script setup lang="ts">
useHead({
titleTemplate: (title) => title ? `${title} %separator %siteName` : '%siteName',
templateParams: { siteName: '我的站点', separator: '·' },
})
</script>
响应式
所有属性都支持 computed、ref 或 getter,可以直接跟着路由或接口数据走:
<script setup lang="ts">
const route = useRoute()
const post = await $fetch(`/api/posts/${route.params.id}`)
useSeoMeta({
title: () => post.title,
description: () => post.excerpt,
ogImage: () => post.image,
})
</script>
与 definePageMeta 联动
有时希望页面级静态信息被其他层读到,放到 definePageMeta 里,再在布局里读:
<script setup lang="ts">
definePageMeta({ title: '某个页面' })
</script>
<!-- 默认布局 -->
<script setup lang="ts">
const route = useRoute()
useHead({
meta: [{ property: 'og:title', content: `我的站点 · ${route.meta.title}` }],
})
</script>
怎么选?
| 你想做的事 | 用哪个 |
|---|---|
| 全站固定标签 | app.head |
| 响应式、任意 head 标签 | useHead |
| 类型安全的 SEO 标签 | useSeoMeta |
| 偏爱模板写法 | <Head> / <Title> 等 |
Body 尾部标签
有些脚本要放在 <body> 末尾,用 tagPosition:
<script setup lang="ts">
useHead({
script: [
{
src: 'https://third-party-script.com',
tagPosition: 'bodyClose',
},
],
})
</script>
useHeadSafe
当你要把用户输入合并进 head,优先用 useHeadSafe。它会过滤掉危险属性(如 innerHTML、事件处理器),防止 XSS。
把元信息当作代码认真维护,这是 Nuxt 里最廉价也最划算的优化之一。