如何使用 NextJS、Notion 和 Notion API 创建博客

2025-06-10

如何使用 NextJS、Notion 和 Notion API 创建博客

在这篇文章中,我想尝试如何使用 Notion 作为数据库来创建一个博客管理系统。我之前写过一篇关于 如何使用 Airtable 创建博客的文章,我在那个项目中用到了 Airtable。现在我正在用 Notion 来做这件事。

我先把这篇文章写到我自己的博客上,也想在这里发布。

首先,我们可以找到有关概念的一切; https://developers.notion.com/ 地址

为我们的博客创建概念集成

我已经看过文档了,我们开始吧。首先,我们应该创建一个集成 https://www.notion.so/my-integrations

概念

在此页面创建一个新的集成。我已创建一个名为“myblog”的集成,以下是我的设置:

基本信息

完成这些步骤后,Notion 将为您提供一个 Notion 令牌,将此令牌复制到安全的地方,我们将使用它来连接我们的数据。

之后,我们需要创建一个页面并将其转换为数据库,以便用于我们的博客。我创建了一个概念页面——数据库完整页面。这是我得到的;

新的

右上角有一个分享按钮,单击该 Share按钮并使用选择器通过名称找到您的集成,然后单击 Invite

我们的集成现在可以访问我们的数据库了,最后一步我们需要数据库 ID。它是 URL 的一部分;

我的是;  https://www.notion.so/yunuserturk/f9dfc334e89e4c2289b9bc98884b5e80

数据库 ID 是; f9dfc334e89e4c2289b9bc98884b5e80

现在我们必须创建我们的应用程序,并且我们可以使用这些概念访问。

创建 NextJS 应用

开始使用 Next.js 的最简单方法是使用 create-next-app 。

使用VS Code创建一个项目,打开终端并使用命令; npx create-next-app

安装 tailwindcss;

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

Enter fullscreen mode Exit fullscreen mode

创建一个粗略的 UI,我从 airtable 项目中复制了代码。

import Head from "next/head";

export default function Home() {
  return (
    <div>
      <Head>
        <title>Create Next App</title>
        <meta name="description" content="Generated by create next app" />
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <main>
        <div className="container mx-auto w-full sm:w-10/12 md:w-8/12 lg:w-6/12 xl:w-6/12 p-4">
          <h1 className="font-bold text-2xl">Welcome to my blog</h1>
          <div className="flex flex-col p-5 rounded-lg border-2 border-gray-200 mt-10">
            <h2 className="text-xl font-bold">Post Title</h2>
            <div>Post Content will be here</div>
            <span className="text-sm mb-6">Post Date</span>
          </div>
        </div>
      </main>
    </div>
  );
}

Enter fullscreen mode Exit fullscreen mode

如何使用 Notion API 并显示内容

我们的主页已经准备好了,现在我们需要获取数据并将其显示在页面上。让我们使用 来安装 Notion 客户端 SDK  npm install @notionhq/client,并在终端上运行此命令。创建一个文件 lib>notion.js ,我们将在这里使用我们的数据库。在文档的帮助下,我创建了一个入门代码。

import { Client } from "@notionhq/client";

const notion = new Client({
  auth: process.env.NEXT_PUBLIC_NOTION_TOKEN,
});

export const getDatabase = async (databaseId) => {
  const response = await notion.databases.query({
    database_id: databaseId,
  });
  return response.results;
};

export const getPage = async (pageId) => {
  const response = await notion.pages.retrieve({ page_id: pageId });
  return response;
};

export const getBlocks = async (blockId) => {
  const blocks = [];
  let block;
  while (true) {
    const { results, next_block } = await notion.blocks.children.list({
      start_block: block,
      block_id: blockId,
    });
    blocks.push(...results);
    if (!next_block) {
      break;
    }
    block = next_block;
  }
  return blocks;
}

Enter fullscreen mode Exit fullscreen mode

我们将把它导入到索引页,获取数据并在主页上显示帖子。使用 Notion API,getpage 函数仅获取页面的属性。我们无法检索页面块。我们必须创建另一个函数并使用 API 来检索页面内容。Notion 将它们称为块,并为此提供了另一个函数。

我的最终index.js页面是这样的;

import Head from "next/head";
import { getDatabase } from "../lib/notion";
import Link from "next/link";

export default function Home({ posts }) {

  return (
    <div>
      <Head>
        <title>Create Next App</title>
        <meta name="description" content="Generated by create next app" />
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <main>
        <div className="container mx-auto w-full sm:w-10/12 md:w-8/12 lg:w-6/12 xl:w-6/12 p-4">
          <h1 className="font-bold text-2xl">Welcome to my blog</h1>
          {posts.map((post) => {
            const date=new Date(post.created_time).toLocaleString("en-Us",{
              month: "long",
              day: "numeric",
              year: "numeric",
              })
            return (
              <div className="flex flex-col p-5 rounded-lg border-2 border-gray-200 mt-10" key={post.id}>
                <h2 className="text-xl font-bold">{post.properties.Name.title[0].plain_text}</h2>
                <span className="text-sm">{date}</span>
                <Link href="/[post]" as={`/${post.id}`}>
                  <a className="text-sm">Read more</a>
                </Link>
              </div>
            );
          })}
        </div>
      </main>
    </div>
  );
}

export const getStaticProps = async () => {
  const database = await getDatabase("f9dfc334e89e4c2289b9bc98884b5e80");

  return {
    props: {
      posts: database,
    },
    revalidate: 1,
  };
};

Enter fullscreen mode Exit fullscreen mode

Notion 为我们提供了带有丰富属性的 API 块。您可以根据需要使用其中的任意一个。但我只使用了文本块,以及段落和标题块。您可以根据项目的具体情况调整要使用的块。(我们将在单篇文章页面上使用它。)

这是单个帖子页面文件;

import { getDatabase, getPage, getBlocks } from "../lib/notion";
import Head from "next/head";

const renderBlock = (block) => {
  const { type } = block;
  const value = block[type];

  switch (type) {
    case "paragraph":
      return <p className="mb-4">{value.rich_text[0].plain_text}</p>;
    case "heading_1":
      return <h1 className="font-bold text-3xl  mb-2">{value.rich_text[0].plain_text}</h1>;
    case "heading_2":
      return <h2 className="font-bold text-2xl  mb-2">{value.rich_text[0].plain_text}</h2>;
    case "heading_3":
      return <h3 className=" font-bold text-xl mb-2">{value.rich_text[0].plain_text}</h3>;
  }
};

export default function Post({ post, content }) {
  const date = new Date(post.created_time).toLocaleString("en-Us", {
    month: "long",
    day: "numeric",
    year: "numeric",
  });
  return (
    <div>
      <Head>
        <title>{post.properties.Name.title[0].plain_text}</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <main>
        <div className="container mx-auto w-full sm:w-10/12 md:w-8/12 lg:w-6/12 xl:w-6/12 p-4">
          <h1 className="font-bold text-2xl">{post.properties.Name.title[0].plain_text}</h1>
          <span className="text-sm">{date}</span>
          <img src="<https://picsum.photos/800/200>" alt="random image" className=" max-w-full" />
          <div className="mt-10">
            {content.map((block) => {
              console.log(block);
              return <div key={block.id}>{block.type === "page_break" ? <hr /> : <div>{renderBlock(block)}</div>}</div>;
            })}
          </div>
        </div>
      </main>
    </div>
  );
}

export const getStaticPaths = async () => {
  const database = await getDatabase("f9dfc334e89e4c2289b9bc98884b5e80");
  const paths = database.map((post) => {
    return {
      params: {
        post: post.id,
      },
    };
  });
  return {
    paths,
    fallback: false,
  };
};

export const getStaticProps = async ({ params }) => {
  const postId = params.post;
  const post = await getPage(postId);
  const content = await getBlocks(postId);

  return {
    props: {
      post,
      content,
    },
    revalidate: 1,
  };
};

Enter fullscreen mode Exit fullscreen mode

这是最终的帖子页面;

最终的

部署和结果

我终于把它部署到 Vercel 上了。这是 Nation API 的一个非常基本的用法,如果你创建了一些更特别的东西,也可以用这种方式。

您可以从 github repo 中看到所有代码: https://github.com/yunuserturk/notion-blog

以下是最终结果的演示: https://notion-blog-yunuserturk.vercel.app/

鏂囩珷鏉ユ簮锛�https://dev.to/yunuserturk/how-to-create-a-blog-with-nextjs-notion-and-notion-api-4fnm
PREV
无障碍:是什么、为什么以及如何
NEXT
Firefox 的新多行控制台编辑器非常棒