NextJS中文文档 - Metadata And Og Images
元数据 API 可用于定义你的应用程序元数据,以改善 SEO 和网页分享效果,包括:
- 静态
metadata
对象 - 动态
generateMetadata
函数 - 特殊的文件约定,可用于添加静态或动态生成的网站图标和 OG 图片。
使用以上任何选项,Next.js 都会自动为你的页面生成相关的 <head>
标签,你可以在浏览器的开发者工具中查看这些标签。
默认字段
即使路由没有定义元数据,也会始终添加两个默认的 meta
标签:
- meta charset 标签设置网站的字符编码。
- meta viewport 标签设置网站的视口宽度和缩放比例,以适应不同的设备。
html
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
1
2
2
其他元数据字段可以通过 Metadata
对象(用于静态元数据)或 generateMetadata
函数(用于生成的元数据)来定义。
静态元数据
要定义静态元数据,从静态的 layout.js
或 page.js
文件中导出一个 Metadata
对象。例如,要为博客路由添加标题和描述:
tsx
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: '我的博客',
description: '...',
}
export default function Page() {}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
jsx
export const metadata = {
title: '我的博客',
description: '...',
}
export default function Page() {}
1
2
3
4
5
6
2
3
4
5
6
你可以在 generateMetadata
文档中查看完整的可用选项列表。
生成的元数据
你可以使用 generateMetadata
函数来 fetch
依赖于数据的元数据。例如,获取特定博客文章的标题和描述:
tsx
import type { Metadata, ResolvingMetadata } from 'next'
type Props = {
params: Promise<{ id: string }>
searchParams: Promise<{ [key: string]: string | string[] | undefined }>
}
export async function generateMetadata(
{ params, searchParams }: Props,
parent: ResolvingMetadata,
): Promise<Metadata> {
const slug = (await params).slug
// 获取文章信息
const post = await fetch(`https://api.vercel.app/blog/${slug}`).then((res) => res.json())
return {
title: post.title,
description: post.description,
}
}
export default function Page({ params, searchParams }: Props) {}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
jsx
export async function generateMetadata({ params, searchParams }, parent) {
const slug = (await params).slug
// 获取文章信息
const post = await fetch(`https://api.vercel.app/blog/${slug}`).then((res) => res.json())
return {
title: post.title,
description: post.description,
}
}
export default function Page({ params, searchParams }) {}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
在后台,Next.js 会将元数据与 UI 分开流式传输,并在元数据解析完成后立即将其注入到 HTML 中。
记忆化数据请求
在某些情况下,你可能需要为元数据和页面本身获取相同的数据。为了避免重复请求,你可以使用 React 的 cache
函数来记忆化返回值,只获取一次数据。例如,为元数据和页面获取博客文章信息:
tsx
import { cache } from 'react'
import { db } from '@/app/lib/db'
// getPost 将被使用两次,但只执行一次
export const getPost = cache(async (slug: string) => {
const res = await db.query.posts.findFirst({ where: eq(posts.slug, slug) })
return res
})
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
jsx
import { cache } from 'react'
import { db } from '@/app/lib/db'
// getPost 将被使用两次,但只执行一次
export const getPost = cache(async (slug) => {
const res = await db.query.posts.findFirst({ where: eq(posts.slug, slug) })
return res
})
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
tsx
import { getPost } from '@/app/lib/data'
export async function generateMetadata({ params }: { params: { slug: string } }) {
const post = await getPost(params.slug)
return {
title: post.title,
description: post.description,
}
}
export default async function Page({ params }: { params: { slug: string } }) {
const post = await getPost(params.slug)
return <div>{post.title}</div>
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
jsx
import { getPost } from '@/app/lib/data'
export async function generateMetadata({ params }) {
const post = await getPost(params.slug)
return {
title: post.title,
description: post.description,
}
}
export default async function Page({ params }) {
const post = await getPost(params.slug)
return <div>{post.title}</div>
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
基于文件的元数据
以下是可用的特殊元数据文件:
你可以将这些用于静态元数据,或者使用代码以编程方式生成这些文件。
网站图标
网站图标是在书签和搜索结果中代表你的网站的小图标。要为你的应用程序添加网站图标,请创建一个 favicon.ico
并将其添加到 app 文件夹的根目录。
你也可以使用代码以编程方式生成网站图标。查看网站图标文档了解更多信息。
静态 Open Graph 图片
Open Graph (OG) 图片是在社交媒体中代表你的网站的图片。要为你的应用程序添加静态 OG 图片,请在 app 文件夹的根目录创建一个 opengraph-image.png
文件。
你也可以通过在文件夹结构的更深层次创建 opengraph-image.png
来为特定路由添加 OG 图片。例如,要为 /blog
路由创建特定的 OG 图片,请在 blog
文件夹中添加一个 opengraph-image.jpg
文件。
更具体的图片将优先于文件夹结构中其上方的任何 OG 图片。
其他图片格式如
jpeg
、png
和webp
也受支持。查看 Open Graph 图片文档了解更多信息。
生成的 Open Graph 图片
ImageResponse
构造函数允许你使用 JSX 和 CSS 生成动态图片。这对于依赖数据的 OG 图片很有用。
例如,要为每个博客文章生成唯一的 OG 图片,请在 blog
文件夹中添加一个 opengraph-image.ts
文件,并从 next/og
导入 ImageResponse
构造函数:
tsx
import { ImageResponse } from 'next/og'
import { getPost } from '@/app/lib/data'
// 图片元数据
export const size = {
width: 1200,
height: 630,
}
export const contentType = 'image/png'
// 图片生成
export default async function Image({ params }: { params: { slug: string } }) {
const post = await getPost(params.slug)
return new ImageResponse(
(
// ImageResponse JSX 元素
<div
style={{
fontSize: 128,
background: 'white',
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
{post.title}
</div>
),
)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
jsx
import { ImageResponse } from 'next/og'
import { getPost } from '@/app/lib/data'
// 图片元数据
export const size = {
width: 1200,
height: 630,
}
export const contentType = 'image/png'
// 图片生成
export default async function Image({ params }) {
const post = await getPost(params.slug)
return new ImageResponse(
(
// ImageResponse JSX 元素
<div
style={{
fontSize: 128,
background: 'white',
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
{post.title}
</div>
),
)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
ImageResponse
支持常见的 CSS 属性,包括 flexbox 和绝对定位、自定义字体、文本换行、居中和嵌套图片。查看支持的 CSS 属性完整列表。
注意事项:
- 示例可在 Vercel OG Playground 中查看。
ImageResponse
使用@vercel/og
、satori
和resvg
将 HTML 和 CSS 转换为 PNG。- 仅支持 flexbox 和部分 CSS 属性。高级布局(如
display: grid
)将无法工作。