第 5 课:第一次真实重构

这一课和前几课不一样。

前几课更多是在讲"应该怎么理解"。

这一课开始,我们正式进入:

真的动手把一个页面拆成组件

这次我已经把任务页完成了第一批重构,拆出了 3 个组件:

  1. TaskPageHeader.vue
  2. TaskStatsCards.vue
  3. TaskFilterBar.vue

你现在要学的重点不是"拆出了几个文件",

而是:

为什么先拆这 3 个,而不是别的部分?


这次重构涉及哪些文件

新增文件

  • src/components/tasks/TaskPageHeader.vue
  • src/components/tasks/TaskStatsCards.vue
  • src/components/tasks/TaskFilterBar.vue

更新文件

  • src/views/TasksView.vue
  • src/types/task.ts

先看重构前的 TasksView.vue 有什么问题

重构前,这个页面虽然能跑,也不算写坏了,但已经出现了典型的"大页面信号":

  • 头部模板和业务逻辑混在一起
  • 统计卡片模板和表格模板放在同一个文件里
  • 筛选栏的结构和筛选状态逻辑也都堆在一起
  • 读代码时很难只聚焦某一块职责

也就是说:

它不是不能维护,

但已经开始"读起来越来越费劲"。

这就是第一次重构最合适的时机。


为什么这次先拆 3 个组件

因为它们满足两个条件:

  1. 职责边界清楚
  2. 拆出去后不会马上把状态流弄复杂

这很重要。

初学者第一次拆组件,

不要一上来就拆最复杂的弹窗表单,

而要先拆"清晰、稳定、低风险"的区域。

所以这次我优先拆了:

  • 页面头部
  • 统计卡片
  • 筛选栏

这是一种非常稳的重构顺序。


第一个组件:TaskPageHeader.vue

它负责的事情非常单纯:

  • 显示标题
  • 显示描述
  • 显示"新增任务"按钮

它对父组件的唯一输出就是:

  • create 事件

所以你可以把它理解成:

一个很轻的交互型组件

它不是页面控制中心,

它只是:

用户点击按钮 -> 通知父组件

这类组件特别适合作为第一次拆分练手对象。


第二个组件:TaskStatsCards.vue

这个组件更简单,它属于典型的:

纯展示组件

它做的事情是:

  • 接收 stats
  • 循环渲染卡片

它几乎不负责业务逻辑,也不管理状态。

所以它是初学组件化时最值得优先拆的一类组件。

你以后如果看到这种区域:

  • 数据已经算好了
  • 组件只负责显示

那基本都很适合先抽出来。


第三个组件:TaskFilterBar.vue

这个组件比前两个更有教学价值。

因为它已经不是纯展示了,

而是一个典型的:

有输入、有交互、有输出的组件

它的输入是:

  • keyword
  • statusFilter
  • priorityFilter
  • statusOptions
  • priorityOptions

它的输出是:

  • keyword-change
  • status-change
  • priority-change

这说明它已经具备了完整的组件边界:

  • 输入靠 props
  • 输出靠 emits

这就是你以后写业务组件时最常见的模式。


为什么筛选栏没有自己保存筛选状态

这是这次重构里最关键的设计点之一。

我们没有把:

  • keyword
  • statusFilter
  • priorityFilter

都放进 TaskFilterBar.vue 自己内部去管理。

而是让它继续留在 TasksView.vue

原因是:

这些筛选条件会直接影响页面级的 filteredTasks 和 taskStats

所以它们更适合保留在父组件里。

也就是说:

  • 子组件只负责"收集用户输入"
  • 父组件负责"拿这些输入去驱动页面业务"

这就是一个非常重要的组件化思维。


这次重构后,父组件发生了什么变化

重构后的 TasksView.vue 更像一个"页面编排层"。

它现在更专注于这些内容:

  • 持有主数据 tasks
  • 持有筛选状态
  • 持有弹窗状态
  • 计算 filteredTasks
  • 计算 taskStats
  • 处理新增任务逻辑
  • 把状态和事件分发给各个子组件

这说明父组件的职责更清楚了:

负责页面级状态和业务组织

而不是既写业务,又写所有细节模板。


这就是"组合页"的雏形

现在的 TasksView.vue 已经开始具备一种很好的结构:

vue 复制代码
<TaskPageHeader />
<TaskStatsCards />
<TaskFilterBar />
<el-table ... />
<el-dialog ... />

这意味着页面开始从:

一大块复杂代码

变成:

多个职责明确的区块组合

这就是你以后在中大型 Vue 项目里最常见的页面组织方式。


为什么这次没有马上拆表格和弹窗

这是一个非常值得你学的决定。

很多初学者重构时容易冲动:

既然都拆了,那就一次性全拆完

但这通常不是最稳的方式。

这次没有马上拆表格和弹窗,是因为:

1. 表格里还有展示规则函数依赖

例如:

  • getStatusType
  • getPriorityType

这些逻辑和页面当前状态还贴得比较近。


2. 弹窗表单是当前页面最复杂的一块

它涉及:

  • dialogVisible
  • taskForm
  • resetTaskForm
  • createTask
  • 表单默认值
  • 表单校验

这块如果第一次重构就直接拆,

对于初学者来说,状态流会一下子变复杂。

所以更稳的策略是:

先拆简单区块,再拆复杂区块

这也是我为什么把它留到下一轮。


这次重构额外补了什么

除了拆组件,这次我还补了通用类型:

  • TaskStatusFilter
  • TaskPriorityFilter
  • TaskStatCard

这一步的意义是:

让父组件和子组件共享同一套数据定义

如果没有这些类型,

每个组件都自己写一遍,后面很容易不统一。

所以你也要慢慢形成习惯:

组件一多,就要开始考虑共享类型


这次重构最值得你学的 3 个点

1. 不是所有组件都一样

当前 3 个组件就已经体现了 3 种典型角色:

  • TaskPageHeader.vue
    轻交互组件
  • TaskStatsCards.vue
    纯展示组件
  • TaskFilterBar.vue
    输入输出明确的交互组件

这说明:

组件化不是一种固定模板,而是多种职责形态


2. 组件拆分后,状态边界更重要

你不能只想着"模板拆出去了",

还要问自己:

  • 状态应该放哪儿?
  • 谁负责计算结果?
  • 谁负责抛出事件?

这才是组件化真正难也真正有价值的部分。


3. 重构要循序渐进

这次只拆了第一批组件。

这不是没拆完,而是故意控制节奏。

因为好的重构通常是:

  • 每次只改一层复杂度
  • 每次都保证页面还能稳定运行
  • 每次都让结构比之前更清晰

这比一次性大改更稳、更适合学习。


你现在应该能回答的 10 个问题

  1. 为什么这次优先拆的是头部、统计卡片、筛选栏?
  2. 为什么统计卡片是典型的纯展示组件?
  3. 为什么筛选栏已经具备组件化边界?
  4. 为什么筛选状态还应该保留在父组件里?
  5. 拆组件后父组件最主要的职责变成了什么?
  6. 为什么这次没有立刻拆表格?
  7. 为什么这次没有立刻拆弹窗表单?
  8. 为什么共享类型在组件变多后会越来越重要?
  9. props + emits 解决的到底是什么问题?
  10. 为什么"渐进式重构"比"一次性重写"更适合实战?

这节课的动手练习

练习 1

先打开这三个组件文件:

  • src/components/tasks/TaskPageHeader.vue
  • src/components/tasks/TaskStatsCards.vue
  • src/components/tasks/TaskFilterBar.vue

然后分别回答:

  • 它负责什么
  • 它接收什么
  • 它输出什么

目的:

训练你按组件边界来读代码。


练习 2

打开 src/views/TasksView.vue,找到这 3 类内容:

  • 页面级状态
  • 传给子组件的 props
  • 从子组件接回来的事件

目的:

训练你看懂父子组件的数据流。


练习 3

试着自己判断:

如果下一步要继续拆,应该先拆:

  • 表格
    还是
  • 弹窗

并说明理由。

目的:

练习"重构优先级判断",而不是只会照着拆。


这节课的复习结论

把这次真实重构压缩成 8 句话:

  1. 第一次重构要先拆边界清晰、风险低的区域。
  2. 头部、统计卡片、筛选栏是当前任务页最适合的第一批组件。
  3. TaskStatsCards.vue 是纯展示组件。
  4. TaskPageHeader.vue 是轻交互组件。
  5. TaskFilterBar.vue 是有明确输入输出的交互组件。
  6. 页面级状态仍然保留在父组件里更稳。
  7. 父组件现在更像页面业务编排中心。
  8. 渐进式重构比一次性大拆更适合学习和实战。
相关推荐
NINGMENGb3 小时前
从“已爆发”到“将爆发”——Infoseek舆情系统重构预警的时间线
重构·舆情系统·舆情监测·舆情监测系统·舆情处置
科技小花11 小时前
数据治理平台架构演进观察:AI原生设计如何重构企业数据管理范式
数据库·重构·架构·数据治理·ai-native·ai原生
盟接之桥16 小时前
盟接之桥®制造业EDI软件,打通全球供应链“最后一公里”,赋能中国制造连接世界
网络·安全·低代码·重构·汽车·制造
北京软秦科技有限公司17 小时前
IA-Lab AI 检测报告生成助手:从“慢、错、贵、难控”到高效稳定,重构TIC行业报告生产逻辑
重构
DeepSCRM18 小时前
跨境 SaaS 架构深度解析:如何利用浏览器指纹隔离与 AI 矩阵重构海外私域流量池?
大数据·人工智能·重构
CHU72903518 小时前
在线教学课堂APP功能版块设计方案:重构学习场景的交互逻辑
java·学习·小程序·重构
AI先驱体验官18 小时前
实时交互数字人:企业服务场景的技术落地分析
大数据·运维·人工智能·重构·aigc
love530love19 小时前
从零搭建本地版 Claurst:基于 Rust 重构的 Claude Code 终端编码助手 + LM Studio 模型接入测试
开发语言·人工智能·windows·重构·rust·lm studio·claude code
量子炒饭大师19 小时前
【C++11】Cyber骇客的 亡骸剥离与右值重构 ——【右值引用 与 移动语义】(附带完整代码解析)
java·c++·重构·c++11·右值引用·移动语义