TDK

2026年9月6日

TDK = Title、Description、Keywords,对应 <title><meta name="description"><meta name="keywords">。App Router 导出 metadatagenerateMetadata,框架写进 <head>,不必手拼整段。


各自干什么

  • title:标签页和搜索结果标题,对点击率影响最大。每页要能区分开。
  • description:结果页摘要。引擎可能改写,仍值得写清「这一页解决什么」。大约 150 字内作参考。
  • keywords:主题词。主流引擎几乎不当排序信号,别堆砌;给自己 CMS / 内部分类用即可。

静态 metadata

根布局给默认值,子页面覆盖或按字段合并:

import type { Metadata } from "next";

export const metadata: Metadata = {
  title: {
    default: "技术博客",
    template: "%s | 技术博客",
  },
  description: "按主题查阅学习笔记。",
  keywords: ["Next.js", "笔记"],
};
tsx

子页只写 title: "首页" 时,完整标题常是 首页 | 技术博客。本站 Pages Router 用的是自定义 Seo 组件,效果同类。


generateMetadata

标题依赖 [id]、查询串或接口时:

import type { Metadata, ResolvingMetadata } from "next";

type Props = { params: Promise<{ id: string }> };

export async function generateMetadata(
  { params }: Props,
  parent: ResolvingMetadata
): Promise<Metadata> {
  const { id } = await params;
  const parentMeta = await parent;
  const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`);
  if (!res.ok) return { title: "未找到" };
  const post = await res.json();

  return {
    title: post.title,
    description: String(post.body).slice(0, 150),
    keywords: [post.title],
  };
}
tsx

parent 是祖先已经解析好的 metadata,可拿来拼站点名、继承 OG 图。同一请求在 generateMetadata 和页面组件之间会被 memo,不必打两遍。

还要读 ?tab= 时,把 searchParams 一并 await


其它常用字段

相对路径的图要先设 metadataBase,才能拼出绝对地址:

export const metadata: Metadata = {
  metadataBase: new URL("https://example.com"),
  robots: { index: true, follow: true },
  icons: { icon: "/favicon.ico" },
  openGraph: { images: ["/og.png"] },
};
ts

openGraphtwitterrobots、PWA 相关下次几篇展开。先保证每页 title / description 不重复、不空。


参考文档