Skip to content

SEO Meta

useSeoMetauseServerSeoMeta 是专门用于 SEO 元标签的组合式函数,语法比 useHead 更简洁、类型更安全。

useSeoMeta vs useHead

方式设置标题设置 OG 标签类型安全语法
useHeadtitle: 'xxx'meta: [{ property: 'og:title', content: 'xxx' }]❌ 属性名是字符串繁琐
useSeoMetatitle: 'xxx'ogTitle: 'xxx'✅ 有完整类型提示简洁

useSeoMeta 的优势

  • 语法简洁ogTitle 代替 { property: 'og:title', content: '...' }
  • 类型安全:所有属性名都有 TypeScript 提示
  • 去重:自动处理同名标签的覆盖,不会重复

推荐

SEO 相关的标签统一用 useSeoMeta,其他 Head 标签用 useHead

useSeoMeta

ts
useSeoMeta({
  title: '我的页面',
  ogTitle: '社交分享标题',
  description: '页面描述',
  ogDescription: '社交分享描述',
  ogImage: 'https://example.com/og.png',
  ogUrl: 'https://example.com/page',
  twitterCard: 'summary_large_image',
})

响应式

ts
const { data: article } = await useFetch('/api/article/1')

useSeoMeta({
  title: () => `${article.value?.title} - 我的博客`,
  description: () => article.value?.excerpt ?? '',
  ogTitle: () => article.value?.title ?? '',
  ogDescription: () => article.value?.excerpt ?? '',
  ogImage: () => article.value?.coverImage ?? '',
})

响应式写法

使用 getter 函数 () => value,当数据变化时 SEO 标签自动更新。

INFO

SSR 时的注意事项:SEO 标签在 SSR 时就需要正确设置(搜索引擎读取的是 HTML 源码) 确保在 useFetch 完成后(await 之后)再调用 useSeoMeta

useServerSeoMeta

仅在服务端设置的 SEO meta,不会发送到客户端

ts
useServerSeoMeta({
  title: '我的页面',
  description: '页面描述',
  ogTitle: '社交分享标题',
  ogDescription: '社交分享描述',
  ogImage: 'https://example.com/og.png',
})

为什么需要 useServerSeoMeta

  • 搜索引擎只能看到 HTML 源码,SEO meta 在服务端设置就够了
  • 不发送到客户端可以减小 Payload 大小
  • 客户端不需要这些数据(不需要响应式更新)

推荐

纯 SEO 标签用 useServerSeoMeta,需要客户端响应式更新的用 useSeoMeta

常用 SEO Meta 属性

基础 SEO

属性对应标签说明示例
title<title>页面标题'我的页面'
descriptionmeta[name=description]页面描述'这是关于...'
robotsmeta[name=robots]爬虫指令'index, follow'
canonicallink[rel=canonical]规范 URL'https://example.com/page'

Open Graph

属性对应标签说明
ogTitlemeta[property=og:title]分享标题
ogDescriptionmeta[property=og:description]分享描述
ogImagemeta[property=og:image]分享图片
ogUrlmeta[property=og:url]页面 URL
ogTypemeta[property=og:type]内容类型
ogSiteNamemeta[property=og:site_name]站点名
ogLocalemeta[property=og:locale]语言

Twitter

属性对应标签说明
twitterCardmeta[name=twitter:card]卡片类型
twitterTitlemeta[name=twitter:title]标题
twitterDescriptionmeta[name=twitter:description]描述
twitterImagemeta[name=twitter:image]图片
twitterSitemeta[name=twitter:site]站点账号

robots 元标签

控制搜索引擎对页面的抓取行为:

ts
useSeoMeta({
  robots: 'index, follow',           // ✅ 允许索引(默认行为)
  // robots: 'noindex, nofollow',    // ❌ 禁止索引(如后台页面)
  // robots: 'noindex, follow',      // 不索引但跟踪链接
  // robots: 'index, nofollow',      // 索引但不跟踪链接
  // robots: 'noimageindex',         // 不索引图片
})

何时设置 noindex

  • 后台管理页面
  • 用户设置页面
  • 搜索结果页
  • 临时页面
  • 重复内容页面

JSON-LD 结构化数据

JSON-LD 是搜索引擎推荐的结构化数据格式,可以让搜索结果显示更丰富的信息(评分、价格、日期等):

ts
useHead({
  script: [
    {
      type: 'application/ld+json',
      children: JSON.stringify({
        '@context': 'https://schema.org',
        '@type': 'Article',
        name: article.value?.title,
        description: article.value?.excerpt,
        author: {
          '@type': 'Person',
          name: 'Author Name',
        },
        datePublished: article.value?.publishedAt,
        dateModified: article.value?.updatedAt,
        image: article.value?.coverImage,
      }),
    },
  ],
})

常用 JSON-LD 类型

ts
// 产品
{
  '@type': 'Product',
  name: '产品名',
  description: '产品描述',
  image: '产品图片',
  offers: {
    '@type': 'Offer',
    price: '99.00',
    priceCurrency: 'CNY',
    availability: 'https://schema.org/InStock',
  },
}

// 面包屑导航
{
  '@type': 'BreadcrumbList',
  itemListElement: [
    { '@type': 'ListItem', position: 1, name: '首页', item: 'https://example.com' },
    { '@type': 'ListItem', position: 2, name: '博客', item: 'https://example.com/blog' },
    { '@type': 'ListItem', position: 3, name: '文章标题' },
  ],
}

// FAQ
{
  '@type': 'FAQPage',
  mainEntity: [
    { '@type': 'Question', name: '问题1', acceptedAnswer: { '@type': 'Answer', text: '答案1' } },
  ],
}

完整示例——文章页 SEO

vue
<script setup lang="ts">
const route = useRoute()
const config = useRuntimeConfig()
const { data: article } = await useFetch(`/api/articles/${route.params.id}`)

const canonicalUrl = computed(() =>
  `${config.public.siteUrl}/blog/${route.params.id}`
)

// SEO 元标签(仅服务端)
useServerSeoMeta({
  title: () => `${article.value?.title} - 我的博客`,
  description: () => article.value?.excerpt ?? '',
  ogTitle: () => article.value?.title ?? '',
  ogDescription: () => article.value?.excerpt ?? '',
  ogImage: () => article.value?.coverImage ?? `${config.public.siteUrl}/default-og.png`,
  ogUrl: () => canonicalUrl.value,
  ogType: 'article',
  ogSiteName: '我的博客',
  ogLocale: 'zh_CN',
  twitterCard: 'summary_large_image',
  twitterTitle: () => article.value?.title ?? '',
  twitterDescription: () => article.value?.excerpt ?? '',
  twitterImage: () => article.value?.coverImage ?? '',
})

// canonical URL
useHead({
  link: [
    { rel: 'canonical', href: () => canonicalUrl.value },
  ],
})

// JSON-LD 结构化数据
useHead({
  script: [
    {
      type: 'application/ld+json',
      children: () => JSON.stringify({
        '@context': 'https://schema.org',
        '@type': 'Article',
        name: article.value?.title,
        description: article.value?.excerpt,
        author: { '@type': 'Person', name: article.value?.author },
        datePublished: article.value?.publishedAt,
        image: article.value?.coverImage,
      }),
    },
  ],
})
</script>

SEO 最佳实践

  1. 每个页面都设置 titledescription:这是最基本的 SEO 要求
  2. 使用 useServerSeoMeta:SEO 标签不需要客户端,减小 Payload
  3. 设置 canonical URL:避免重复内容问题
  4. 设置 Open Graph 标签:确保社交分享时显示正确信息
  5. 动态页面设置 og:url:避免同一内容被不同 URL 索引
  6. 后台页面设置 noindex:不需要搜索引擎索引的页面
  7. 添加 JSON-LD:让搜索结果显示更丰富的信息

知识脉络

text
Head 管理 → 你在这里:SEO Meta

             ├─→ 下一步:Open Graph 与 Twitter

             └─→ 相关:服务端开发 → 服务路由(sitemap / robots)

基于 Nuxt 4 官方文档整理编写