OK,OK,大家好,欢迎大家来到大鹏 AI 教育,我是张大鹏。
这篇继续做 RuyiLibraryAdmin 图书管理系统。
前面我们已经做了模块化、主题系统和 CSS Modules。代码不再全部堆在 App.tsx,样式也不再全部堆在 styles.css。
但做到这里,还有一个问题必须继续解决:页面内部还是会越来越大。
比如仪表盘里有顶部概览、统计卡片、借阅趋势图、分类柱状图、近期借阅表。
图书管理页里有页面标题、搜索筛选、操作按钮、表格字段、状态标签。
VIP 升级页里有头图、价值点、套餐卡片、交付路径。
如果这些内容都堆在一个页面文件里,文件还是会慢慢变成新的"大杂烩"。
所以这一篇,我们做组件化开发。
先看现在的页面效果
这是当前的仪表盘。

从 UI 上看,它是一张完整页面。
但从代码上看,它不应该是一个完整大组件。
它至少应该拆成:
- 顶部运营概览
- 指标卡片组
- 借阅趋势图
- 热门分类图
- 近期借阅表
这样做的目的不是为了目录好看,而是为了让每一块 UI 都有自己的职责。
后续我要改趋势图,就去改趋势图组件。
我要改指标卡片,就去改指标组件。
我要改近期借阅表,就去改借阅表组件。
这就是组件化的价值。
AI 开发为什么更需要组件化?
AI 写 React 页面很快。
你让它写一个仪表盘,它可以一次生成几百行 JSX。
刚开始很爽。
但问题是,AI 后面继续改这个文件时,也会面对几百行上下文。
它可能为了改一个表格字段,顺手影响图表。
也可能为了改一个按钮,把页面布局也改掉。
这不是 AI 故意乱改,而是边界不清楚。
组件化就是给 AI 画边界。
比如以后我可以这样下指令:
text
只修改 src/features/books/components/BooksTable.tsx。
不要修改 BooksPage.tsx。
不要修改 shared/ui/DataTable。
修改后运行 pnpm build。
这个任务就很清楚。
AI 不需要理解整个系统,只需要改一个小组件。
我选择的方案:shared 基础组件 + feature 业务组件
这次我没有把所有组件都扔到 components/ 目录。
那样看起来简单,但项目一大就会乱。
我采用的是双层结构:
text
shared 基础组件 + feature 业务组件
shared/ui 放跨模块复用的基础组件。
比如:
text
src/shared/ui/DataTable.tsx
src/shared/ui/ListPage.tsx
src/shared/ui/PanelTitle.tsx
src/shared/ui/StatCard.tsx
src/shared/ui/Status.tsx
这些组件不属于某一个业务。
图书、借阅、读者、分类都会用表格。
很多页面都会用标题、面板、状态标签。
所以它们适合放到 shared。
业务组件则放在自己的 feature 下面。
比如图书管理自己的表格:
text
src/features/books/components/BooksTable.tsx
借阅管理自己的表格:
text
src/features/loans/components/LoansTable.tsx
这样一看目录,就知道组件属于哪里。
仪表盘怎么拆?
重构前,DashboardPage.tsx 里同时有统计计算、图表配置、表格渲染和页面布局。
这次我把它拆成了 5 个组件:
text
src/features/dashboard/components/
DashboardHero.tsx
MetricGrid.tsx
LoanTrendChart.tsx
CategoryChart.tsx
RecentLoansTable.tsx
现在 DashboardPage.tsx 只负责组装:
tsx
export function DashboardPage() {
return (
<div className={styles.stack}>
<DashboardHero />
<MetricGrid />
<div className={styles.gridTwo}>
<LoanTrendChart />
<CategoryChart />
</div>
<RecentLoansTable />
</div>
);
}
这就是我想要的页面文件。
它读起来像页面大纲,而不是一坨实现细节。
以后要讲课,也更容易讲。
先讲页面由哪几块组成,再进入每个组件看细节。
图书、借阅、读者、分类怎么拆?
这几个页面都是后台系统最常见的列表页。

它们的页面结构很像:
- 页面标题
- 页面说明
- 搜索筛选
- 新增按钮
- 数据表格
所以页面壳子继续复用 ListPage。
但表格字段和数据映射属于业务模块,不能一直写在页面里。
于是我拆成:
text
features/books/components/BooksTable.tsx
features/loans/components/LoansTable.tsx
features/readers/components/ReadersTable.tsx
features/categories/components/CategoriesTable.tsx
这样 BooksPage.tsx 就变得非常薄:
tsx
export function BooksPage() {
return (
<ListPage title="图书馆藏" desc="管理书名、作者、ISBN、分类、库存和馆藏位置。" action="新增图书">
<BooksTable />
</ListPage>
);
}
这个结构很适合 AI 开发。
以后要加图书状态颜色、库存告警、ISBN 链接,基本都进 BooksTable。
页面不需要跟着变。
组件拆到什么程度才合适?
组件化不是拆得越碎越好。
我一般按三个标准判断。
第一,这块 UI 有没有独立业务含义。
比如 LoanTrendChart 有明确含义,值得拆。
第二,这块 UI 会不会单独修改。
比如 BooksTable 后续肯定会加字段、状态、操作,值得拆。
第三,这块 UI 会不会复用。
比如 DataTable 多个页面都用,就应该放到 shared/ui。
反过来,如果只是两三行普通标签,不需要为了拆而拆。
过度组件化会让目录变复杂,也会让新手找不到代码。
组件化的目标不是"文件变多",而是"职责变清楚"。
这次拆完后的结构
这次组件化之后,核心目录变成这样:
text
src/features/
dashboard/
DashboardPage.tsx
components/
DashboardHero.tsx
MetricGrid.tsx
LoanTrendChart.tsx
CategoryChart.tsx
RecentLoansTable.tsx
books/
BooksPage.tsx
components/
BooksTable.tsx
loans/
LoansPage.tsx
components/
LoansTable.tsx
readers/
ReadersPage.tsx
components/
ReadersTable.tsx
categories/
CategoriesPage.tsx
components/
CategoriesTable.tsx
internal/
AboutPage.tsx
vipContent.ts
components/
VipHero.tsx
VipFeatureGrid.tsx
VipPackageGrid.tsx
VipDeliveryTimeline.tsx
可以看到,每个页面都更薄了。
页面文件负责组装。
业务组件负责具体展示。
共享组件负责基础 UI。
这就是一个后台项目比较舒服的结构。
登录页也要看,但这次不继续拆
登录页现在也已经独立成页面模块,并有自己的 CSS Module。
这次的验证
组件化重构后,我会继续跑:
bash
pnpm build
pnpm exec playwright test tests/e2e/theme.spec.ts
pnpm screenshots:003
这三步分别验证:
- TypeScript 和构建没问题
- 主题切换没被组件拆分破坏
- 关键页面还能稳定截图
纯 AI 开发一定要养成这个习惯。
不是拆完觉得"应该没问题",而是用构建和截图证明没问题。
下一步
下一步可以继续在组件化结构上加真实功能。
我会优先做:
第一,BooksTable 增加操作列。
第二,新增 BookFormDialog,实现新增图书弹窗。
第三,LoansTable 增加还书和续借操作。
第四,把这些功能继续写成图文博客。
到这里,项目已经有了一个比较清晰的演进路线:
先页面跑通。
再模块化。
再主题和 CSS 模块化。
再组件化。
之后再加真实业务功能。
这样做纯 AI 开发,节奏会稳很多。
AI 负责快速实现,人负责拆边界、定规范、做验收。