Skip to content

meta相关处理

配置形式

nuxt.config.ts
export default defineNuxtConfig({
app: {
head: {
charset: 'utf-8',
viewport: 'width=device-width, initial-scale=1',
meta: [
// ....
],
},
},
})

head 能够配置的项目有:

{
"meta": [
{
"name": "viewport",
"content": "width=device-width, initial-scale=1"
},
{
"charset": "utf-8"
}
],
"link": [],
"style": [],
"script": [],
"noscript": []
}

例如:

app: {
head: {
meta: [
// <meta name="viewport" content="width=device-width, initial-scale=1">
{ name: 'viewport', content: 'width=device-width, initial-scale=1' }
],
script: [
// <script src="https://myawesome-lib.js"></script>
{ src: 'https://awesome-lib.js' }
],
link: [
// <link rel="stylesheet" href="https://myawesome-lib.css">
{ rel: 'stylesheet', href: 'https://awesome-lib.css' }
],
// please note that this is an area that is likely to change
style: [
// <style type="text/css">:root { color: red }</style>
{ children: ':root { color: red }', type: 'text/css' }
],
noscript: [
// <noscript>JavaScript is required</noscript>
{ children: 'JavaScript is required' }
]
}
}

另外关于这些值的类型:

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/schema 包中定义的,具体可以查看 unhead schema 的源码

组合式函数

配置的形式往往都是写死的,并且所有页面通用的。无法使用响应式数据,Nuxt 中提供了组合式函数 useHead 来为 meta 信息提供响应式的修改。相比配置文件的形式,useHead 的优势在于:

<script setup lang="ts">
useHead({
title: '用户管理系统',
meta: [{ name: 'description', content: '这是一个 Nuxt3 网站' }],
bodyAttrs: {
class: 'test',
},
script: [{ innerHTML: "console.log('Hello world')" }],
})
</script>

除了 useHead 以外,还有一个 useHeadSafe:

例如:

const userInput = '<script>alert("恶意代码")</script>'
useHeadSafe({
title: () => userInput,
})

两者的对比如下:

特性useHeaduseHeadSafe
安全性无自动转义,需手动处理不安全内容自动转义,防止 XSS 攻击
适用场景可信内容(硬编码或已清理的数据)不可信内容(用户输入、外部数据源)
性能无额外处理开销轻微开销(转义操作)
动态内容支持支持响应式对象和函数同样支持响应式对象和函数

因此在使用时建议优先使用 useHeadSafe,特别是当内容来自用户输入、URL 参数、数据库或第三方 API 时,始终使用 useHeadSafe。在内容完全可信(如静态字符串)时可以使用 useHead,使用时避免直接插入未经验证的动态内容。

除了 head 相关的组合式函数以外,Nuxt 中还提供了一个专门处理 meta 的组合式函数 useSeoHead。虽然 useHead 也能够设置 meta 信息,例如:

useHead({
title: '我的页面标题', // 设置标题
script: [{ src: '/analytics.js' }], // 插入脚本
link: [{ rel: 'icon', href: '/favicon.ico' }] // 插入链接
meta: [
{ name: 'description', content: '页面描述' }, // 普通 meta 标签
{ property: 'og:title', content: 'Open Graph 标题' }, // Open Graph 标签
{ name: 'twitter:card', content: 'summary_large_image' } // Twitter 卡片标签
]
});

不过使用 useSeoHead 能够简化常见 SEO 属性的配置,useSeoHead 具备如下特点:

useSeoMeta({
title: '我的页面标题', // 自动设置 <title> 和 og:title
description: '页面描述', // 自动设置 description 和 og:description
ogTitle: 'Open Graph 标题', // 自动转换为 property="og:title"
twitterCard: 'summary_large_image', // 自动转换为 name="twitter:card"
ogImage: 'https://example.com/image.jpg', // 自动处理为 og:image
})

两者之间的对比如下表:

特性useHeaduseSeoMeta
设计目标通用头部管理专注于 SEO Meta 标签优化
语法需手动编写 HTML 标签结构语义化键名(驼峰式 → 自动转换)
类型安全基础类型支持强类型提示(SEO 专用键名)
安全性需手动处理动态内容(依赖 useHeadSafe自动转义动态内容
适用场景任意 <head> 标签操作仅 SEO 相关 meta 标签(title、og、twitter 等)
代码简洁性较低(需完整结构)较高(简化配置)

相关组件

Nuxt 提供了一系列与 <head> 相关的组件,允许开发者直接在 Vue 模板中声明式地操作页面元数据(SEO 相关标签)。这些组件包括:

注意事项:

  1. 书写时需大写:因为这些是组件,需要防止和原生 html 元素冲突

  2. 实际渲染位置由 Nuxt 自动控制,不会因为嵌套关系改变。这种设计主要是为了代码可读性和逻辑组织,而非影响渲染结果。

  3. 所有组件属性均支持 Vue 的响应式数据

    <template>
    <Title>{{ title }}</Title>
    <Meta name="description" :content="description" />
    </template>
    <script setup>
    const title = ref('Hello World')
    const description = ref('动态描述')
    </script>
  4. 一些组件支持 children 属性,用于直接插入子内容。例如 <Style> 组件

    <Style type="text/css" children="body { background-color: green; }" />
    <style type="text/css">
    body {
    background-color: green;
    }
    </style>

示例:

<template>
<div>
<!-- Head 组件包裹其他 SEO 组件 -->
<Head>
<!-- 动态标题 -->
<Title>{{ title }}</Title>
<!-- 动态 meta 描述 -->
<Meta name="description" :content="title" />
<!-- 内联样式 -->
<Style type="text/css" children="body { background-color: green; }" />
</Head>
<!-- 页面内容 -->
<h1>{{ title }}</h1>
</div>
</template>
<script setup lang="ts">
const title = ref('Hello World')
</script>

渲染效果:

<html>
<head>
<title>Hello World</title>
<meta name="description" content="Hello World" />
<style type="text/css">
body {
background-color: green;
}
</style>
</head>
<body>
<div>
<h1>Hello World</h1>
</div>
</body>
</html>

-EOF-