---
title: "SEO 和元数据"
description: "使用强大的 head 配置、组合式函数和组件来提升你的 Nuxt 应用的 SEO。"
canonical_url: "https://nuxt.zhcndoc.com/docs/4.x/getting-started/seo-meta"
---
# SEO 和元数据

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

Nuxt 的 head 标签管理由 [Unhead](https://unhead.unjs.io) 提供支持。它提供了合理的默认值、若干强大的组合式函数以及众多配置选项来管理应用的 head 和 SEO 元标签。

## Nuxt 配置

在 [`nuxt.config.ts`](https://nuxt.zhcndoc.com/docs/4.x/directory-structure/nuxt-config) 中提供 [`app.head`](https://nuxt.zhcndoc.com/docs/4.x/api/nuxt-config#head) 属性，即可静态自定义整个应用的 head。

<important>

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

</important>

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

```ts [nuxt.config.ts]twoslash
export default defineNuxtConfig({
  app: {
    head: {
      title: 'Nuxt', // 默认回退标题
      htmlAttrs: {
        lang: 'en',
      },
      link: [
        { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
      ],
    },
  },
})
```

<note>

设置 [`app.cdnURL`](https://nuxt.zhcndoc.com/docs/4.x/api/nuxt-config#cdnurl) 后，[`public/`](https://nuxt.zhcndoc.com/docs/4.x/directory-structure/public) 目录中的资源（包括 `favicon.ico`）会从该 CDN 提供。Nuxt 会使用 `cdnURL` 解析公共资源，如果未设置，则回退到 `app.baseURL`。但是，上面这样的静态 `app.head` 链接（例如 `href: '/favicon.ico'`）是字面路径，不会根据 `cdnURL` 解析。要让 favicon 指向解析后的路径，请在 `app.vue` 中使用 [`useHead()`](https://nuxt.zhcndoc.com/docs/4.x/api/composables/use-head) 根据运行时配置构建 `href`：

```vue [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>
```

</note>

你也可以在 [类型](https://nuxt.zhcndoc.com/docs/4.x/getting-started/seo-meta#types)中提供下方列出的任何键。

### 默认标签

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

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

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

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

## `useHead`

[`useHead`](https://nuxt.zhcndoc.com/docs/4.x/api/composables/use-head) 组合式函数支持响应式输入，让你能够以编程方式管理 head 标签。

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

我们建议查看 [`useHead`](https://nuxt.zhcndoc.com/docs/4.x/api/composables/use-head) 和 [`useHeadSafe`](https://nuxt.zhcndoc.com/docs/4.x/api/composables/use-head-safe) 组合式函数。

## `useSeoMeta`

[`useSeoMeta`](https://nuxt.zhcndoc.com/docs/4.x/api/composables/use-seo-meta) 组合式函数可以让你以对象的形式定义网站的 SEO 元标签，并获得完整的类型安全保障。

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

```vue [app/app.vue]twoslash
<script setup lang="ts">
useSeoMeta({
  title: '我的超棒网站',
  ogTitle: '我的超棒网站',
  description: '这是我的超棒网站，让我来为你详细介绍一下。',
  ogDescription: '这是我的超棒网站，让我来为你详细介绍一下。',
  ogImage: 'https://example.com/image.png',
  twitterCard: 'summary_large_image',
})
</script>
```

<read-more to="https://nuxt.zhcndoc.com/docs/4.x/api/composables/use-seo-meta">



</read-more>

## 组件

虽然所有情况下都建议使用 [`useHead`](https://nuxt.zhcndoc.com/docs/4.x/api/composables/use-head)，但你可能更喜欢在模板中使用组件定义 head 标签。

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

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

```vue [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>` 组件中，因为这样标签会以更直观的方式去重。

<warning>

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

</warning>

## 类型

以下是 [`useHead`](https://nuxt.zhcndoc.com/docs/4.x/api/composables/use-head)、[`app.head`](https://nuxt.zhcndoc.com/docs/4.x/api/nuxt-config#head) 和组件所使用的非响应式类型。

```ts [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](https://github.com/unjs/unhead/blob/main/packages/vue/src/types/schema.ts)。

## 功能

### 响应式

所有属性都支持响应式，通过提供一个 computed 值、getter 或响应式对象即可。

<code-group>

```vue [useHead]twoslash
<script setup lang="ts">
const description = ref('My amazing site.')

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

```vue [useSeoMeta]twoslash
<script setup lang="ts">
const description = ref('My amazing site.')

useSeoMeta({
  description,
})
</script>
```

```vue [app/Components]
<script setup lang="ts">
const description = ref('My amazing site.')
</script>

<template>
  <div>
    <Meta
      name="description"
      :content="description"
    />
  </div>
</template>
```

</code-group>

### 标题模板

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

`titleTemplate` 可以是一个字符串（其中 `%s` 将替换为标题），也可以是一个函数。

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

<code-group>

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

</code-group>

现在，如果你在网站的其他页面中使用 [`useHead`](https://nuxt.zhcndoc.com/docs/4.x/api/composables/use-head) 将标题设置为 `My Page`，浏览器标签页中显示的标题将是 'My Page - Site Title'。你也可以传入 `null`，默认使用 'Site Title'。

### 模板参数

你可以使用 `templateParams` 在 `titleTemplate` 中提供默认 `%s` 之外的额外占位符。这可以让标题生成更加灵活。

<code-group>

```vue [useHead]twoslash
<script setup lang="ts">
useHead({
  titleTemplate: (titleChunk) => {
    return titleChunk ? `${titleChunk} %separator %siteName` : '%siteName'
  },
  templateParams: {
    siteName: 'Site Title',
    separator: '-',
  },
})
</script>
```

</code-group>

### Body 标签

你可以在适用的标签上使用 `tagPosition: 'bodyClose'` 选项，将它们追加到 `<body>` 标签的末尾。

例如：

```vuetwoslash
<script setup lang="ts">
useHead({
  script: [
    {
      src: 'https://third-party-script.com',
      // 有效选项为：'head' | 'bodyClose' | 'bodyOpen'
      tagPosition: 'bodyClose',
    },
  ],
})
</script>
```

## 使用 `definePageMeta`

在你的 [`app/pages/` 目录](https://nuxt.zhcndoc.com/docs/4.x/guide/directory-structure/app/pages) 中，你可以将 `definePageMeta` 与 [`useHead`](https://nuxt.zhcndoc.com/docs/4.x/api/composables/use-head) 一起使用，以基于当前路由设置元信息。

在你的 [`app/pages/` 目录](https://nuxt.zhcndoc.com/docs/4.x/directory-structure/app/pages) 中，你可以将 `definePageMeta` 与 [`useHead`](https://nuxt.zhcndoc.com/docs/4.x/api/composables/use-head) 一起使用，以基于当前路由设置元信息。

例如，你可以先设置当前页面标题（该标题会在构建时通过宏提取，因此不能动态设置）：

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

然后在你的布局文件中，你可以使用之前设置的路由元数据：

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

useHead({
  meta: [{ property: 'og:title', content: `应用名称 - ${route.meta.title}` }],
})
</script>
```

<link-example to="https://nuxt.zhcndoc.com/docs/4.x/examples/features/meta-tags">



</link-example>

<read-more to="https://nuxt.zhcndoc.com/docs/4.x/directory-structure/app/pages/#page-metadata">



</read-more>

### 动态标题

在下面的示例中，`titleTemplate` 要么设置为带有 `%s` 占位符的字符串，要么设置为函数，这允许为 Nuxt 应用的每个路由更灵活地动态设置页面标题：

```vue [app/app.vue]twoslash
<script setup lang="ts">
useHead({
  // 作为字符串，
  // 其中 `%s` 会被替换为标题
  titleTemplate: '%s - 站点标题',
})
</script>
```

```vue [app/app.vue]twoslash
<script setup lang="ts">
useHead({
  // 或者作为函数
  titleTemplate: (productCategory) => {
    return productCategory
      ? `${productCategory} - 站点标题`
      : '站点标题'
  },
})
</script>
```

`nuxt.config` 也可以作为设置页面标题的另一种方式。但是，`nuxt.config` 不允许页面标题是动态的。因此，建议在 `app.vue` 文件中使用 `titleTemplate` 来添加动态标题，然后将其应用到 Nuxt 应用的所有路由。

### 外部 CSS

以下示例展示了如何通过 [`useHead`](https://nuxt.zhcndoc.com/docs/4.x/api/composables/use-head) 组合式函数的 `link` 属性或 `<Link>` 组件启用 Google Fonts：

<code-group>

```vue [useHead]twoslash
<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>
```

```vue [app/Components]
<template>
  <div>
    <Link
      rel="preconnect"
      href="https://fonts.googleapis.com"
    />
    <Link
      rel="stylesheet"
      href="https://fonts.googleapis.com/css2?family=Roboto&display=swap"
      crossorigin=""
    />
  </div>
</template>
```

</code-group>


## Sitemap

See the full [sitemap](https://nuxt.zhcndoc.com/sitemap.md) for all pages.
