首页/16

16章:博客项目实战:从零到完整

综合运用所有知识,从零搭建一个完整的博客系统

120分钟
4个学习目标

学习目标

  • 1理解项目结构设计的原则
  • 2掌握数据类型定义的最佳实践
  • 3学会组件拆分和组合
  • 4实现完整的CRUD功能

欢迎来到实战章!

恭喜你走到这里!在前面的章节中,你已经掌握了:

  • TypeScript基础类型和接口
  • 函数和泛型
  • 类和面向对象
  • 异步编程
  • 工具类型
  • Next.js页面和API路由
  • React组件

现在是时候把它们组合起来了。

这就像学做菜——你已经学会了切菜、炒菜、调味,现在要做一桌完整的饭菜。

类比理解:

| 前面学的 | 本章要做的 | |---------|----------| | 类型定义 | 设计数据结构 | | API路由 | 处理数据增删改查 | | React组件 | 构建用户界面 | | 组件组合 | 拼装完整页面 |

本章目标: 从零搭建一个完整的博客系统,包括:

  • 文章列表展示
  • 文章详情页面
  • 创建新文章
  • 编辑文章
  • 删除文章
  • 标签分类
  • 搜索功能

第一步:定义数据类型

在开始编写代码之前,我们首先需要定义数据类型。这是TypeScript开发的重要步骤。

为什么先定义类型?

这就像盖房子之前先画图纸

  • 图纸(类型)定义了房子的结构
  • 工人(代码)按照图纸施工
  • 验收(TypeScript)检查是否符合图纸

先定义类型的好处:

  1. 明确数据结构,避免返工
  2. 提供代码提示,写代码更快
  3. 防止类型错误,代码更安全
  4. 作为项目文档,新人容易上手

博客系统需要的类型:

  • Post(文章)
  • User(用户)
  • Comment(评论)

让我们开始定义这些类型。

定义文章类型

typescript
加载中...

类型设计解析

让我们看看这些类型设计的思路:

PostStatus 类型

export type PostStatus = "draft" | "published" | "archived";

使用联合类型,限制文章只能是这三种状态之一。比用字符串更安全——写错字TypeScript会报错。

Post 接口 定义了文章的完整数据结构。每个字段都有明确的类型。

CreatePostInput 接口 创建文章时的输入类型。注意:

  • 不包含id(系统自动生成)
  • 不包含createdAt(系统自动设置)
  • 不包含viewCount(初始为0)

UpdatePostInput 接口 更新文章时的输入类型。所有字段都是可选的——你可能只想改标题,不想改内容。

设计原则:

  • 读取数据用完整类型(Post)
  • 创建数据用精简类型(CreatePostInput)
  • 更新数据用可选类型(UpdatePostInput)

定义用户和评论类型

typescript
加载中...

第二步:创建数据存储

为了简化项目,我们使用本地JSON文件存储数据。在实际项目中,你会使用数据库。

类比理解:

| 存储方式 | 类比 | 适用场景 | |---------|------|---------| | JSON文件 | 手写笔记本 | 学习、原型开发 | | SQLite | 个人日记本 | 小型项目 | | PostgreSQL | 企业档案柜 | 生产环境 |

为什么先用JSON文件?

  1. 不需要安装数据库
  2. 数据持久化(重启不会丢失)
  3. 易于理解和调试
  4. 可以轻松迁移到数据库

数据存储结构:

data/
├── posts.json     # 存储所有文章
├── users.json     # 存储所有用户
└── comments.json  # 存储所有评论

让我们创建数据操作的工具函数。

数据操作函数

typescript
加载中...

第三步:创建API路由

有了数据操作函数,现在让我们创建API路由,让前端能够访问这些数据。

RESTful API设计:

| 方法 | 路径 | 功能 | |------|------|------| | GET | /api/posts | 获取所有文章 | | GET | /api/posts/:id | 获取单篇文章 | | POST | /api/posts | 创建文章 | | PUT | /api/posts/:id | 更新文章 | | DELETE | /api/posts/:id | 删除文章 |

类比理解:

RESTful API就像图书馆的借阅系统

  • GET = 查看(不修改)
  • POST = 新增一本书
  • PUT = 修改书的信息
  • DELETE = 删除一本书

文章API路由

typescript
加载中...

第四步:创建前端页面

现在让我们创建前端页面来展示和管理文章。

页面结构:

| 页面 | 路径 | 功能 | |------|------|------| | 首页 | / | 文章列表 | | 文章详情 | /posts/[id] | 查看文章 | | 创建文章 | /posts/create | 新建文章 | | 编辑文章 | /posts/[id]/edit | 修改文章 |

组件设计:

| 组件 | 功能 | |------|------| | PostCard | 文章卡片(标题、摘要、标签) | | PostList | 文章列表(包含多个PostCard) | | PostForm | 文章表单(创建/编辑) | | SearchBar | 搜索栏 |

让我们从文章卡片组件开始。

文章卡片组件

typescript
加载中...

第五步:实现搜索功能

搜索功能是博客系统的重要组成部分。让我们实现一个简单的搜索功能。

搜索实现思路:

  1. 创建搜索API端点
  2. 在前端添加搜索框
  3. 根据关键词过滤文章
  4. 显示搜索结果

搜索逻辑:

  • 搜索文章标题
  • 搜索文章内容
  • 搜索标签
  • 支持模糊匹配(不区分大小写)

搜索API和组件

typescript
加载中...

常见错误

常见错误

错误1:类型定义和实际数据不匹配

// 定义了createdAt是Date,但JSON解析后是string
interface Post {
  createdAt: Date;  // 期望Date
}

// JSON.parse后是string!
const post = JSON.parse(data); // post.createdAt 是 "2024-01-01"

// 解决:转换日期
const post = {
  ...JSON.parse(data),
  createdAt: new Date(parsed.createdAt),
};

错误2:忘记处理异步错误

// 错误!没有try-catch
export async function GET() {
  const posts = await getAllPosts(); // 如果失败会崩溃
  return NextResponse.json(posts);
}

// 正确
export async function GET() {
  try {
    const posts = await getAllPosts();
    return NextResponse.json(posts);
  } catch (error) {
    return NextResponse.json({ error: "获取失败" }, { status: 500 });
  }
}

错误3:组件Props类型不一致

// 传了Date对象,但组件期望string
<PostCard post={{ ...post, createdAt: new Date() }} />

// 组件内用new Date(post.createdAt)处理
// 如果传的是Date,new Date(Date)还是Date,不会报错
// 但如果传的是string,需要确保格式正确

动手实践

现在轮到你了!基于上面的代码,完成以下练习:

练习1:完善文章详情页面 创建 /app/posts/[id]/page.tsx:

  • 从API获取文章数据
  • 显示文章标题、内容、作者、日期
  • 添加"编辑"和"删除"按钮

练习2:实现文章编辑功能 创建 /app/posts/[id]/edit/page.tsx:

  • 加载现有文章数据到表单
  • 提交时调用PUT /api/posts/:id
  • 成功后跳转到文章详情页

练习3:添加文章删除功能 在文章详情页面添加删除功能:

  • 点击删除按钮弹出确认框
  • 确认后调用DELETE /api/posts/:id
  • 成功后跳转到首页

练习4:实现文章列表分页

  • 修改API支持分页参数(page, limit)
  • 在前端添加分页组件
  • 显示"上一页"和"下一页"按钮

提示:

  • 使用useRouter进行页面跳转
  • 使用window.confirm进行确认
  • 使用try-catch处理API错误

项目总结与知识回顾

恭喜你完成了整个博客项目!让我们回顾一下你学到的所有知识:

TypeScript核心知识:

| 章节 | 知识点 | 在项目中的应用 | |------|--------|--------------| | 基础类型 | string, number, boolean, 数组 | 定义文章标题、浏览次数、标签数组 | | 接口 | interface | 定义Post、User、Comment结构 | | 函数 | 参数类型、返回值类型 | API处理函数、工具函数 | | 类 | class、继承 | 可选:面向对象的数据模型 | | 泛型 | <T> | 泛型列表组件、API响应类型 | | 工具类型 | Partial, Pick, Omit | UpdatePostInput用Partial实现 | | 异步编程 | async/await | API数据获取、文件读写 |

Next.js知识:

| 知识点 | 在项目中的应用 | |--------|--------------| | 文件系统路由 | /, /posts/[id], /posts/create | | 服务器组件 | 文章列表页面、详情页面 | | 客户端组件 | 搜索栏、表单 | | 布局 | 共享导航栏和页脚 | | API路由 | /api/posts, /api/posts/[id] |

React知识:

| 知识点 | 在项目中的应用 | |--------|--------------| | 函数组件 | PostCard, SearchBar, PostForm | | Props类型 | 组件的输入定义 | | useState | 搜索关键词、表单状态 | | 事件处理 | 表单提交、按钮点击 |

项目架构:

my-blog/
├── app/                    # 页面和API
│   ├── layout.tsx         # 根布局
│   ├── page.tsx           # 首页
│   ├── posts/
│   │   ├── [id]/
│   │   │   ├── page.tsx   # 文章详情
│   │   │   └── edit/
│   │   │       └── page.tsx # 编辑文章
│   │   └── create/
│   │       └── page.tsx   # 创建文章
│   └── api/
│       └── posts/
│           ├── route.ts   # 文章API
│           ├── [id]/
│           │   └── route.ts
│           └── search/
│               └── route.ts
├── components/            # 可复用组件
│   ├── PostCard.tsx
│   ├── PostForm.tsx
│   └── SearchBar.tsx
├── lib/                   # 工具函数
│   └── posts.ts
├── types/                 # 类型定义
│   ├── post.ts
│   ├── user.ts
│   └── comment.ts
└── data/                  # 数据文件
    ├── posts.json
    ├── users.json
    └── comments.json

后续学习建议

你已经完成了TypeScript + Next.js的基础学习!接下来可以继续深入:

短期目标(1-2周):

  1. 部署项目 - 使用Vercel一键部署
  2. 添加数据库 - 使用Prisma + SQLite/PostgreSQL
  3. 用户认证 - 使用NextAuth.js实现登录
  4. 样式优化 - 深入学习Tailwind CSS

中期目标(1-2个月):

  1. 测试 - 学习Jest和React Testing Library
  2. 状态管理 - 学习Zustand或Jotai
  3. 性能优化 - 学习Next.js的缓存策略
  4. CI/CD - 自动化测试和部署

长期目标(3-6个月):

  1. 全栈框架 - 深入学习Next.js高级特性
  2. AI集成 - 使用Vercel AI SDK添加AI功能
  3. 微服务 - 学习系统架构设计
  4. 开源贡献 - 参与开源项目

学习资源推荐:

  • 官方文档:nextjs.org/docs, typescriptlang.org
  • 视频教程:YouTube搜索"Next.js tutorial"
  • 实战项目:GitHub搜索"next.js projects"
  • 社区:Reddit r/nextjs, Discord

最后的话:

TypeScript和Next.js是现代Web开发的核心技能。你已经迈出了重要的一步——从零开始搭建了一个完整的博客系统。

记住:最好的学习方式是动手实践。不要只是看教程,要自己写代码、踩坑、解决问题。

祝你学习愉快,期待看到你的作品!

交互式练习

1 / 1

定义文章类型

根据需求定义一个完整的文章接口

typescript
Loading...

章节测验

问题 1 / 3得分: 0 / 3

在TypeScript中,定义接口使用什么关键字?

A
type
B
interface
C
class
D
enum