Nuxt.js元数据与SEO #
一、SEO概述 #
搜索引擎优化(SEO)对于网站的可见性至关重要。Nuxt.js 通过服务端渲染(SSR)和完善的元数据管理,为 SEO 提供了强大的支持。
1.1 Nuxt.js的SEO优势 #
- 服务端渲染:搜索引擎可以直接抓取完整内容
- 元数据管理:灵活的
useHead组合式函数 - 站点地图:自动生成 sitemap
- 结构化数据:支持 JSON-LD
二、useHead基础 #
2.1 基本用法 #
vue
<script setup lang="ts">
useHead({
title: '页面标题',
meta: [
{ name: 'description', content: '页面描述' }
]
})
</script>
2.2 支持的属性 #
vue
<script setup lang="ts">
useHead({
title: '页面标题',
titleTemplate: (title) => `${title} - 我的网站`,
meta: [
{ name: 'description', content: '页面描述' },
{ name: 'keywords', content: '关键词1, 关键词2' },
{ name: 'author', content: '作者名' },
{ name: 'robots', content: 'index, follow' }
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
{ rel: 'canonical', href: 'https://example.com/page' }
],
script: [
{ src: '/script.js', defer: true }
],
style: [
{ children: 'body { margin: 0; }' }
],
htmlAttrs: {
lang: 'zh-CN'
},
bodyAttrs: {
class: 'dark-mode'
}
})
</script>
三、页面标题 #
3.1 静态标题 #
vue
<script setup lang="ts">
useHead({
title: '关于我们'
})
</script>
3.2 动态标题 #
vue
<script setup lang="ts">
const { data: article } = await useFetch('/api/article/1')
useHead({
title: computed(() => article.value?.title || '加载中...')
})
</script>
3.3 标题模板 #
在 nuxt.config.ts 中设置全局模板:
typescript
export default defineNuxtConfig({
app: {
head: {
titleTemplate: '%s - 我的网站'
}
}
})
页面中使用:
vue
<script setup lang="ts">
useHead({
title: '首页'
})
</script>
结果:首页 - 我的网站
3.4 自定义模板 #
vue
<script setup lang="ts">
useHead({
title: '文章详情',
titleTemplate: (title) => `${title} | 博客 | 我的网站`
})
</script>
四、Meta标签 #
4.1 基本Meta #
vue
<script setup lang="ts">
useHead({
meta: [
{ name: 'description', content: '这是页面描述,用于搜索引擎展示' },
{ name: 'keywords', content: 'Nuxt.js, Vue.js, SSR' },
{ name: 'author', content: '作者名' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ name: 'robots', content: 'index, follow' }
]
})
</script>
4.2 Open Graph #
vue
<script setup lang="ts">
useHead({
meta: [
{ property: 'og:title', content: '分享标题' },
{ property: 'og:description', content: '分享描述' },
{ property: 'og:image', content: 'https://example.com/image.png' },
{ property: 'og:url', content: 'https://example.com/page' },
{ property: 'og:type', content: 'article' },
{ property: 'og:site_name', content: '我的网站' }
]
})
</script>
4.3 Twitter Card #
vue
<script setup lang="ts">
useHead({
meta: [
{ name: 'twitter:card', content: 'summary_large_image' },
{ name: 'twitter:title', content: '分享标题' },
{ name: 'twitter:description', content: '分享描述' },
{ name: 'twitter:image', content: 'https://example.com/image.png' },
{ name: 'twitter:site', content: '@twitter_handle' }
]
})
</script>
4.4 动态Meta #
vue
<script setup lang="ts">
const { data: article } = await useFetch('/api/article/1')
useHead({
meta: [
{
name: 'description',
content: computed(() => article.value?.excerpt || '')
},
{
property: 'og:title',
content: computed(() => article.value?.title || '')
},
{
property: 'og:image',
content: computed(() => article.value?.coverImage || '/default-og.png')
}
]
})
</script>
五、Link标签 #
5.1 常用Link #
vue
<script setup lang="ts">
useHead({
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
{ rel: 'apple-touch-icon', sizes: '180x180', href: '/apple-touch-icon.png' },
{ rel: 'canonical', href: 'https://example.com/page' },
{ rel: 'alternate', type: 'application/rss+xml', href: '/rss.xml' }
]
})
</script>
5.2 CSS样式表 #
vue
<script setup lang="ts">
useHead({
link: [
{ rel: 'stylesheet', href: 'https://fonts.googleapis.com/css2?family=Roboto' }
]
})
</script>
5.3 预加载和预连接 #
vue
<script setup lang="ts">
useHead({
link: [
{ rel: 'preconnect', href: 'https://fonts.googleapis.com' },
{ rel: 'preconnect', href: 'https://fonts.gstatic.com', crossorigin: true },
{ rel: 'preload', href: '/fonts/custom.woff2', as: 'font', type: 'font/woff2', crossorigin: true }
]
})
</script>
六、全局配置 #
6.1 nuxt.config.ts #
typescript
export default defineNuxtConfig({
app: {
head: {
title: '我的网站',
titleTemplate: '%s - 我的网站',
meta: [
{ name: 'description', content: '网站描述' },
{ name: 'keywords', content: '关键词1, 关键词2' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ charset: 'utf-8' }
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
],
htmlAttrs: {
lang: 'zh-CN'
}
}
}
})
6.2 app.config.ts #
typescript
export default defineAppConfig({
title: '我的网站',
description: '网站描述',
ogImage: '/og-image.png'
})
使用:
vue
<script setup lang="ts">
const appConfig = useAppConfig()
useHead({
meta: [
{ property: 'og:image', content: appConfig.ogImage }
]
})
</script>
七、结构化数据 #
7.1 JSON-LD #
vue
<script setup lang="ts">
const { data: article } = await useFetch('/api/article/1')
useHead({
script: [
{
type: 'application/ld+json',
children: JSON.stringify({
'@context': 'https://schema.org',
'@type': 'Article',
headline: article.value?.title,
description: article.value?.excerpt,
author: {
'@type': 'Person',
name: article.value?.author
},
datePublished: article.value?.publishedAt,
dateModified: article.value?.updatedAt
})
}
]
})
</script>
7.2 产品结构化数据 #
vue
<script setup lang="ts">
const { data: product } = await useFetch('/api/product/1')
useHead({
script: [
{
type: 'application/ld+json',
children: JSON.stringify({
'@context': 'https://schema.org',
'@type': 'Product',
name: product.value?.name,
description: product.value?.description,
image: product.value?.images,
offers: {
'@type': 'Offer',
price: product.value?.price,
priceCurrency: 'CNY',
availability: 'https://schema.org/InStock'
}
})
}
]
})
</script>
八、站点地图 #
8.1 安装模块 #
bash
pnpm add @nuxtjs/sitemap
8.2 配置 #
typescript
export default defineNuxtConfig({
modules: ['@nuxtjs/sitemap'],
site: {
url: 'https://example.com'
},
sitemap: {
sources: ['/api/sitemap']
}
})
8.3 动态站点地图 #
server/api/sitemap.ts:
typescript
export default defineEventHandler(async () => {
const posts = await $fetch('/api/posts')
return posts.map(post => ({
loc: `/blog/${post.slug}`,
lastmod: post.updatedAt,
changefreq: 'weekly',
priority: 0.8
}))
})
九、robots.txt #
9.1 配置 #
typescript
export default defineNuxtConfig({
robots: {
UserAgent: '*',
Allow: '/',
Disallow: ['/admin', '/private'],
Sitemap: 'https://example.com/sitemap.xml'
}
})
9.2 动态robots.txt #
server/routes/robots.txt.ts:
typescript
export default defineEventHandler(() => {
return `User-agent: *
Allow: /
Disallow: /admin
Disallow: /private
Sitemap: https://example.com/sitemap.xml`
})
十、SEO最佳实践 #
10.1 完整示例 #
pages/blog/[slug].vue:
vue
<script setup lang="ts">
const route = useRoute()
const { data: article } = await useFetch(`/api/articles/${route.params.slug}`)
if (!article.value) {
throw createError({ statusCode: 404, message: '文章不存在' })
}
const canonicalUrl = computed(() =>
`https://example.com/blog/${route.params.slug}`
)
useHead({
title: article.value.title,
meta: [
{ name: 'description', content: article.value.excerpt },
{ name: 'keywords', content: article.value.tags?.join(', ') },
{ name: 'author', content: article.value.author },
{ name: 'robots', content: 'index, follow' },
{ property: 'og:title', content: article.value.title },
{ property: 'og:description', content: article.value.excerpt },
{ property: 'og:image', content: article.value.coverImage },
{ property: 'og:url', content: canonicalUrl },
{ property: 'og:type', content: 'article' },
{ property: 'article:published_time', content: article.value.publishedAt },
{ property: 'article:author', content: article.value.author },
{ name: 'twitter:card', content: 'summary_large_image' },
{ name: 'twitter:title', content: article.value.title },
{ name: 'twitter:description', content: article.value.excerpt },
{ name: 'twitter:image', content: article.value.coverImage }
],
link: [
{ rel: 'canonical', href: canonicalUrl }
],
script: [
{
type: 'application/ld+json',
children: JSON.stringify({
'@context': 'https://schema.org',
'@type': 'Article',
headline: article.value.title,
description: article.value.excerpt,
image: article.value.coverImage,
author: {
'@type': 'Person',
name: article.value.author
},
datePublished: article.value.publishedAt,
dateModified: article.value.updatedAt,
mainEntityOfPage: {
'@type': 'WebPage',
'@id': canonicalUrl.value
}
})
}
]
})
</script>
<template>
<article>
<header>
<h1>{{ article.title }}</h1>
<p>{{ article.publishedAt }} · {{ article.author }}</p>
</header>
<div v-html="article.content" />
</article>
</template>
10.2 SEO检查清单 #
- [ ] 每个页面有唯一的标题
- [ ] 每个页面有描述性 meta description
- [ ] 使用语义化 HTML 标签
- [ ] 图片有 alt 属性
- [ ] 设置 canonical URL
- [ ] 添加 Open Graph 标签
- [ ] 添加 Twitter Card 标签
- [ ] 生成站点地图
- [ ] 配置 robots.txt
- [ ] 添加结构化数据
十一、总结 #
本章介绍了 Nuxt.js 元数据与 SEO:
- 使用
useHead管理页面元数据 - 配置页面标题和模板
- 添加 Open Graph 和 Twitter Card
- 使用结构化数据增强搜索展示
- 生成站点地图和配置 robots.txt
- SEO 最佳实践
良好的 SEO 可以显著提升网站的搜索引擎排名和流量,下一章我们将学习数据获取。
最后更新:2026-03-28