Nuxt: SEO 优化 useHead + useSeoMeta
最后更新:2026-08-26
Charlie 的 MegaShop 有百万商品页,但 Google 只索引了 2 thousand。Alice 搜商品名都找不到 MegaShop 的页面。Bob 检查发现:商品页没有 title、没有 meta description、没有 Open Graph 标签、没有结构化数据。Nuxt 3 的 SEO 工具链能解决这一切。
1. 你将学到
- useHead():动态管理 title/meta/link/script/style
- useSeoMeta():结构化 SEO 元数据(OG/Twitter/description)
- Nuxt 3 内置 SEO 默认值与覆盖机制
- Sitemap 与 robots.txt:@nuxtjs/sitemap 模块
- MegaShop 商品详情页动态 SEO + JSON-LD + Sitemap 自动生成
2. 一个架构师的真实故事
(1) 痛点:百万页只有 2 thousand 被 Google 收录
Charlie 用 Google Search Console 检查 MegaShop,发现 1 million 商品页只有 2 thousand 被索引。Bob 分析发现:所有商品页的 title 都是 "MegaShop",meta description 为空,Open Graph 缺失——社交媒体分享时只显示网站名,没有商品信息。
(2) Nuxt SEO 工具链的解法
Nuxt 3 的 useHead + useSeoMeta 让每个商品页有独立的 SEO 元数据:
TYPESCRIPT
// pages/products/[id].vue
useSeoMeta({
title: product.value?.name,
ogTitle: product.value?.name,
description: `Buy ${product.value?.name} for $${product.value?.price} USD`,
ogImage: product.value?.image
})
(3) 收益:Google 索引率飙升 40 倍
3 个月后,Google 索引从 2 thousand 飙升到 800 thousand,有机搜索流量增长 340%。
3. SEO 工具链架构
(1) Nuxt 3 SEO 工具链全景
graph TB
A[Nuxt SEO Toolkit] --> B[useHead]
A --> C[useSeoMeta]
A --> D[JSON-LD]
A --> E[@nuxtjs/sitemap]
A --> F[robots.txt]
B --> B1[title / meta / link]
C --> C1[OG / Twitter Card]
D --> D1[Product / Breadcrumb]
E --> E1[Dynamic URL Generation]
F --> F1[Crawler Access Control]
```
---
## 4. useHead 动态管理
### (1) useHead 能管理什么
| 标签类型 | 属性 | SEO 影响 |
|:---------|:-----|:---------|
| title | 页面标题 | 🔴 高(排名信号) |
| meta name="description" | 页面描述 | 🔴 高(点击率) |
| meta property="og:*" | Open Graph | 🟡 中(社交分享) |
| meta name="twitter:*" | Twitter Card | 🟡 中(社交分享) |
| link rel="canonical" | 规范 URL | 🔴 高(去重) |
| link rel="alternate" | 多语言 URL | 🟡 中(i18n SEO) |
| script type="application/ld+json" | JSON-LD | 🟡 中(富片段) |
### ▶ 示例:useHead 基础用法
```typescript
// In any component or page
useHead({
title: 'Premium Headphones - MegaShop',
meta: [
{ name: 'description', content: 'Buy Premium Headphones for $299.99 USD. Free shipping.' },
{ name: 'keywords', content: 'headphones, wireless, premium, audio' }
],
link: [
{ rel: 'canonical', href: 'https://megashop.com/products/123' }
]
})
输出:
TEXT
📖 仅展示
// 执行成功
▶ 示例:动态 title(computed 响应式)
VUE
<script setup lang="ts">
const route = useRoute()
const { data: product } = await useFetch(`/api/products/${route.params.id}`)
// Dynamic title that updates when product loads
useHead({
title: computed(() => product.value
? `${product.value.name} - MegaShop`
: 'Loading... - MegaShop'
)
})
</script>
输出:
TEXT
📖 仅展示
// 执行成功
▶ 示例:全局默认配置
TYPESCRIPT
// nuxt.config.ts
export default defineNuxtConfig({
app: {
head: {
title: 'MegaShop - Premium E-Commerce',
titleTemplate: '%s | MegaShop',
meta: [
{ name: 'description', content: 'Over 1 million products shipped worldwide' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ charset: 'utf-8' }
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
]
}
}
})
输出:
TEXT
📖 仅展示
// 执行成功
4. useSeoMeta 结构化 SEO
(1) useSeoMeta vs useHead 对比
| 维度 | useHead | useSeoMeta |
|---|---|---|
| 定位 | 通用 Head 管理 | SEO 专用快捷方法 |
| API 风格 | 数组对象 | 键值对 |
| OG/Twitter | 需手动写 meta | 一行搞定 |
| 类型安全 | ⚠️ 需查文档 | ✅ 完整类型提示 |
| 去重 | ⚠️ 手动管理 | ✅ 自动去重 |
▶ 示例:商品详情页 SEO
VUE
<!-- pages/products/[id].vue -->
<script setup lang="ts">
const route = useRoute()
const { data: product } = await useFetch(`/api/products/${route.params.id}`)
// Structured SEO metadata - type-safe
useSeoMeta({
title: () => `${product.value?.name} - Buy Online`,
ogTitle: () => `${product.value?.name} - MegaShop`,
description: () => `Buy ${product.value?.name} for $${product.value?.price} USD. ${product.value?.reviewCount} reviews, ${product.value?.rating} stars. Free shipping worldwide.`,
ogDescription: () => `Premium ${product.value?.name} - $${product.value?.price} USD`,
ogImage: () => product.value?.image || '/images/og-default.jpg',
ogUrl: () => `https://megashop.com/products/${route.params.id}`,
ogType: 'product',
twitterCard: 'summary_large_image',
twitterTitle: () => `${product.value?.name} - MegaShop`,
twitterImage: () => product.value?.image || '/images/og-default.jpg'
})
</script>
输出:
TEXT
📖 仅展示
// 执行成功
▶ 示例:首页 SEO
TYPESCRIPT
// pages/index.vue
useSeoMeta({
title: 'MegaShop - Over 1 Million Products',
ogTitle: 'MegaShop - Premium E-Commerce Platform',
description: 'Shop over 1 million products with free worldwide shipping. Electronics, fashion, home & garden at the best prices.',
ogDescription: 'Discover 1 million+ products on MegaShop. Free shipping on orders over $50 USD.',
ogImage: '/images/og-homepage.jpg',
ogUrl: 'https://megashop.com',
ogType: 'website'
})
输出:
TEXT
📖 仅展示
// 执行成功
5. JSON-LD 结构化数据
(1) 结构化数据对搜索结果的影响
| 数据类型 | Google 富片段效果 | MegaShop 适用 |
|---|---|---|
| Product | 价格/评分/库存 | ✅ 商品详情页 |
| BreadcrumbList | 面包屑导航 | ✅ 所有页面 |
| Organization | 企业信息 | ✅ 首页 |
| WebSite | 站内搜索框 | ✅ 首页 |
| Review | 评价摘要 | ✅ 商品页 |
▶ 示例:商品 JSON-LD
VUE
<!-- pages/products/[id].vue -->
<script setup lang="ts">
const route = useRoute()
const { data: product } = await useFetch(`/api/products/${route.params.id}`)
// JSON-LD structured data for Google rich results
useHead({
script: [
{
type: 'application/ld+json',
innerHTML: computed(() => JSON.stringify({
'@context': 'https://schema.org',
'@type': 'Product',
name: product.value?.name,
image: product.value?.image,
description: product.value?.description,
sku: `MEGA-${product.value?.id}`,
offers: {
'@type': 'Offer',
url: `https://megashop.com/products/${route.params.id}`,
priceCurrency: 'USD',
price: product.value?.price,
availability: product.value?.inStock
? 'https://schema.org/InStock'
: 'https://schema.org/OutOfStock'
},
aggregateRating: {
'@type': 'AggregateRating',
ratingValue: product.value?.rating,
reviewCount: product.value?.reviewCount
}
}))
}
]
})
</script>
输出:
TEXT
📖 仅展示
// 执行成功
▶ 示例:面包屑 JSON-LD
TYPESCRIPT
// composables/useBreadcrumbLd.ts
export function useBreadcrumbLd(items: { name: string; url: string }[]) {
useHead({
script: [{
type: 'application/ld+json',
innerHTML: JSON.stringify({
'@context': 'https://schema.org',
'@type': 'BreadcrumbList',
itemListElement: items.map((item, index) => ({
'@type': 'ListItem',
position: index + 1,
name: item.name,
item: item.url
}))
})
}]
})
}
// Usage in page
useBreadcrumbLd([
{ name: 'Home', url: 'https://megashop.com' },
{ name: 'Products', url: 'https://megashop.com/products' },
{ name: 'Premium Headphones', url: 'https://megashop.com/products/123' }
])
输出:
TEXT
📖 仅展示
// 执行成功
6. Sitemap 与 robots.txt
▶ 示例:安装 @nuxtjs/sitemap
BASH
npm install @nuxtjs/sitemap
输出:
TEXT
📖 仅展示
# 命令执行成功
TYPESCRIPT
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@nuxtjs/sitemap'],
sitemap: {
hostname: 'https://megashop.com',
gzip: true,
routes: async () => {
// Dynamic routes for 1 million products
const products = await $fetch('/api/products/all-ids')
return products.map((id: number) => ({
loc: `/products/${id}`,
lastmod: new Date().toISOString(),
changefreq: 'daily',
priority: 0.8
}))
},
defaults: {
changefreq: 'weekly',
priority: 0.5
}
}
})
▶ 示例:robots.txt
TEXT
📖 仅展示
// public/robots.txt
User-agent: *
Allow: /
Disallow: /admin/
Disallow: /api/
Disallow: /profile/
Sitemap: https://megashop.com/sitemap.xml
输出:
TEXT
📖 仅展示
执行成功
(1) Sitemap 策略对比
| 策略 | 优点 | 缺点 | 适用 |
|---|---|---|---|
| 单文件 sitemap.xml | 简单 | ≤ 50 thousand URL | 小站 |
| Sitemap Index | 支持百万 URL | 需拆分 | MegaShop |
| 动态生成 routes | 自动覆盖新页 | 构建时查询 | 商品页 |
| 模块自动生成 | 零配置 | 有限制 | 中小站 |
7. 综合示例:MegaShop 商品页 SEO 全套
VUE
<!-- pages/products/[id].vue -->
<template>
<div v-if="product" class="product-page">
<h1>{{ product.name }}</h1>
<p class="price">${{ product.price }} USD</p>
<p>{{ product.reviewCount }} reviews · {{ product.rating }} stars</p>
</div>
</template>
<script setup lang="ts">
const route = useRoute()
const config = useRuntimeConfig()
const { data: product } = await useFetch(`/api/products/${route.params.id}`)
const productUrl = `${config.public.siteUrl}/products/${route.params.id}`
// SEO Meta
useSeoMeta({
title: () => `${product.value?.name} - MegaShop`,
ogTitle: () => product.value?.name,
description: () => `Buy ${product.value?.name} for $${product.value?.price} USD. Free shipping. ${product.value?.reviewCount} reviews.`,
ogDescription: () => `${product.value?.name} - $${product.value?.price} USD on MegaShop`,
ogImage: () => product.value?.image,
ogUrl: () => productUrl,
ogType: 'product',
twitterCard: 'summary_large_image'
})
// Canonical URL
useHead({
link: [{ rel: 'canonical', href: productUrl }]
})
// JSON-LD
useHead({
script: [{
type: 'application/ld+json',
innerHTML: computed(() => JSON.stringify({
'@context': 'https://schema.org',
'@type': 'Product',
name: product.value?.name,
image: product.value?.image,
offers: {
'@type': 'Offer',
priceCurrency: 'USD',
price: product.value?.price,
availability: product.value?.inStock ? 'InStock' : 'OutOfStock'
},
aggregateRating: {
'@type': 'AggregateRating',
ratingValue: product.value?.rating,
reviewCount: product.value?.reviewCount
}
}))
}]
})
</script>
❓ 常见问题
Q useSeoMeta 和 useHead 能同时用吗?
A 可以,它们操作同一个 Head 实例。useSeoMeta 管理 SEO 标签,useHead 管理其他标签(canonical/JSON-LD/style)。
Q 百万商品页的 sitemap 怎么处理?
A 用 Sitemap Index 拆分为多个子 sitemap(每个 ≤ 50 thousand URL)。@nuxtjs/sitemap 模块支持自动拆分。
Q JSON-LD 的 innerHTML 有 XSS 风险吗?
A Nuxt 3 会对 script 标签的 innerHTML 做安全处理。但最好对动态数据做 JSON.stringify + 转义,避免注入。
Q SEO 元数据在 CSR 模式下有效吗?
A 搜索引擎爬虫不支持 CSR 渲染的 meta 标签。需要 SEO 的页面必须用 SSR/ISR/SSG。CSR 页面的 meta 只在客户端水合后才出现。
Q titleTemplate 怎么用?
A 在 nuxt.config.ts 设
titleTemplate: '%s | MegaShop',页面 useHead 只需设 title 内容部分,模板自动拼接。Q ogImage 的图片尺寸有要求吗?
A Facebook 推荐 1200x630px,Twitter 推荐 1200x600px(summary_large_image)。图片过小可能不显示。
📖 小节
- useHead 通用管理 Head 标签,useSeoMeta 专注 SEO 元数据,类型更安全
- 动态 SEO:computed 响应式 title/description,每个商品页独立元数据
- JSON-LD 结构化数据让 Google 显示富片段(价格/评分/库存)
- @nuxtjs/sitemap 自动生成 Sitemap,支持百万 URL 的 Sitemap Index
- robots.txt 控制爬虫访问范围,屏蔽 admin/api/profile 路径
📝 作业
- 基础题(难度⭐):用 useHead 为首页设置 title 和 meta description,查看源代码验证
- 进阶题(难度⭐⭐):用 useSeoMeta 为商品详情页配置完整的 OG + Twitter Card 元数据,用 Facebook Sharing Debugger 验证
- 挑战题(难度⭐⭐⭐):实现商品页 JSON-LD + 面包屑 JSON-LD + Sitemap 自动生成,用 Google Rich Results Test 验证结构化数据
---|