SEO 和元数据

使用强大的 head 配置、组合式函数和组件来提升你的 Nuxt 应用的 SEO。

Nuxt 的 head 标签管理由 Unhead 提供支持。它提供了合理的默认值、若干强大的组合式函数以及众多配置选项来管理应用的 head 和 SEO 元标签。

Nuxt 配置

在你的 nuxt.config.ts 中提供一个 app.head 属性,可让你静态地自定义整个应用的 head。

此方法不允许提供响应式数据。我们建议在 app.vue 中使用 useHead()

通常建议在此处设置不会改变的标签,例如站点默认标题、语言和 favicon。

nuxt.config.ts
export default defineNuxtConfig({
  app: {
    head: {
      title: 'Nuxt', // 默认回退标题
      htmlAttrs: {
        lang: 'en',
      },
      link: [
        { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
      ],
    },
  },
})
当你设置 app.cdnURL 时,你的 public/ 目录中的资源(包括 favicon.ico)会从该 CDN 提供。Nuxt 会根据 cdnURL 解析公共资源,并在找不到时回退到 app.baseURL。不过,上面这种静态的 app.head 链接,例如 href: '/favicon.ico',是一个字面路径,不会 根据 cdnURL 进行解析。若要将 favicon 指向解析后的地址,请在 app.vue 中使用 useHead(),并通过运行时配置构建 href
app/app.vue
<script setup lang="ts">
const { cdnURL, baseURL } = useRuntimeConfig().app
useHead({
  link: [
    { rel: 'icon', type: 'image/x-icon', href: `${cdnURL || baseURL}favicon.ico` },
  ],
})
</script>

你也可以提供 Types 中列出的任意键。

默认标签

为确保网站开箱即用,Nuxt 默认提供一些标签以保证良好兼容性。

  • viewport: width=device-width, initial-scale=1
  • charset: utf-8

大多数站点不需要覆盖这些默认值,但你可以使用带键的快捷方式来更新它们。

nuxt.config.ts
export default defineNuxtConfig({
  app: {
    head: {
      // 更新 Nuxt 默认值
      charset: 'utf-16',
      viewport: 'width=device-width, initial-scale=1, maximum-scale=1',
    },
  },
})

useHead

useHead 组合式函数支持响应式输入,允许你以编程方式管理 head 标签。

app/app.vue
<script setup lang="ts">
useHead({
  title: '我的应用',
  meta: [
    { name: 'description', content: '我的精彩网站。' },
  ],
  bodyAttrs: {
    class: 'test',
  },
  script: [{ innerHTML: 'console.log(\'Hello world\')' }],
})
</script>

我们建议查看 useHeaduseHeadSafe 这两个组合式函数。

useSeoMeta

useSeoMeta 组合式函数让你可以将站点的 SEO 元标签以对象形式定义,并提供完整的类型安全。

这有助于你避免拼写错误和常见错误,例如使用 name 而不是 property

app/app.vue
<script setup lang="ts">
useSeoMeta({
  title: '我的超棒网站',
  ogTitle: '我的超棒网站',
  description: '这是我的超棒网站,让我来向你介绍一下。',
  ogDescription: '这是我的超棒网站,让我来向你介绍一下。',
  ogImage: 'https://example.com/image.png',
  twitterCard: 'summary_large_image',
})
</script>
Docs > 4 X > API > Composables > Use Seo Meta 中查看详情

组件

虽然在所有情况下都推荐使用 useHead,但你也可能更倾向于在模板中使用组件来定义 head 标签。

Nuxt 为此提供了以下组件:<Title><Base><NoScript><Style><Meta><Link><Body><Html><Head>。注意这些组件的大小写,以确保我们不使用无效的原生 HTML 标签。

<Head><Body> 可以接受嵌套的元标签(出于审美原因),但这不会影响嵌套元标签在最终 HTML 中的实际渲染位置。

app/app.vue
<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> 组件中,因为标签将更直观地去重。

如果你需要在客户端和服务端之间重复标签,请在 <Head> 组件上应用 key 属性。

类型

下面是用于 useHeadapp.head 和组件的非响应式类型。

Types
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 值、getter 或响应式对象即可。

<script setup lang="ts">
const description = ref('My amazing site.')

useHead({
  meta: [
    { name: 'description', content: description },
  ],
})
</script>

标题模板

你可以使用 titleTemplate 选项为站点标题提供动态模板。例如,你可以在每个页面标题中添加站点名称。

titleTemplate 可以是一个字符串(其中 %s 将替换为标题),也可以是一个函数。

如果你想使用函数(以获得完全的控制),那么不能在 nuxt.config 中设置它。建议改为在你的 app.vue 文件中设置,这样它会应用到站点的所有页面:

<script setup lang="ts">
useHead({
  titleTemplate: (titleChunk) => {
    return titleChunk ? `${titleChunk} - Site Title` : 'Site Title'
  },
})
</script>

现在,如果你在站点的其他页面上使用 useHead 将标题设置为 My Page,浏览器标签中的标题将显示为 'My Page - Site Title'。你也可以传递 null 来默认使用 'Site Title'。

Template Parameters

你可以使用 templateParamstitleTemplate 中提供除了默认 %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',
      // 有效选项为:'head' | 'bodyClose' | 'bodyOpen'
      tagPosition: 'bodyClose',
    },
  ],
})
</script>

Example

Using definePageMeta

In your app/pages/ directory, you can use definePageMeta together with useHead to set metadata based on the current route.

For example, you can first set the current page title (this is extracted at build time via macros, so it cannot be set dynamically):

pages/some-page.vue
<script setup lang="ts">
definePageMeta({
  title: '某页面',
})
</script>

Then in your layout file, you can use the route metadata you set earlier:

layouts/default.vue
<script setup lang="ts">
const route = useRoute()

useHead({
  meta: [{ property: 'og:title', content: `应用名称 - ${route.meta.title}` }],
})
</script>
Read and edit a live example in Docs > 4 X > Examples > Features > Meta Tags.
Docs > 4 X > Directory Structure > App > Pages > #page Metadata 中查看详情

Dynamic Titles

In the example below, titleTemplate is either set to a string with a %s placeholder, or set to a function, which allows for more flexible dynamic page title setting for each route of the Nuxt application:

app/app.vue
<script setup lang="ts">
useHead({
  // As a string,
  // where `%s` will be replaced with the title
  titleTemplate: '%s - 站点标题',
})
</script>
app/app.vue
<script setup lang="ts">
useHead({
  // Or as a function
  titleTemplate: (productCategory) => {
    return productCategory
      ? `${productCategory} - 站点标题`
      : '站点标题'
  },
})
</script>

nuxt.config can also be used as another way to set page titles. However, nuxt.config does not allow page titles to be dynamic. Therefore, it is recommended to use titleTemplate in the app.vue file to add dynamic titles, and then apply it to all routes of the Nuxt application.

External CSS

The following example shows how to enable Google Fonts using the link property of useHead or by using the <Link> component:

<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>