Nuxt: SEO 优化 useHead + useSeoMeta

最后更新:2026-08-26

Charlie 的 MegaShop 有百万商品页,但 Google 只索引了 2 thousand。Alice 搜商品名都找不到 MegaShop 的页面。Bob 检查发现:商品页没有 title、没有 meta description、没有 Open Graph 标签、没有结构化数据。Nuxt 3 的 SEO 工具链能解决这一切。

1. 你将学到


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 工具链全景

100%
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)。图片过小可能不显示。

📖 小节


📝 作业

  1. 基础题(难度⭐):用 useHead 为首页设置 title 和 meta description,查看源代码验证
  2. 进阶题(难度⭐⭐):用 useSeoMeta 为商品详情页配置完整的 OG + Twitter Card 元数据,用 Facebook Sharing Debugger 验证
  3. 挑战题(难度⭐⭐⭐):实现商品页 JSON-LD + 面包屑 JSON-LD + Sitemap 自动生成,用 Google Rich Results Test 验证结构化数据

---|

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏