一次业务前端重构:让代码结构对应实际的修改

2025 年底到 2026 年初,我集中重构了一次正在维护的 Vue 业务前端。它从 MVP 开始持续迭代,后来增加了项目列表、资料填写、文件上传和个人设置等页面。功能增加后,请求、表单校验、保存和弹窗控制逐渐集中在页面入口,页面私有组件和公共组件的边界也不太明确。

维护时需要一起检查表单输入、校验和提交转换,上传卡片的状态与回调也由父页面管理。另一边,新增页面除了配置路由,还要修改应用入口里的布局判断。

这次重构主要调整这些职责,让修改一个业务区块时,需要的代码尽量在它自己的范围内。

从申请表单开始

申请页面包含表单、提交成功状态和二维码弹窗。原来表单如何校验、字段如何转换、成功后展示什么,主要都在页面中处理。我把表单和成功状态拆成页面私有组件,页面入口负责装配组件与提交后的流程。

申请表单目录调整前后

表单内部一起管理输入、校验和提交数据转换。比如地区选择器返回数组,接口需要字符串;选择“其他”时,还要合并补充输入。这些处理都依赖具体字段,和输入控件放在一起,修改字段时可以同时检查。

校验通过后,表单通过 emit 提交处理好的数据,页面执行提交操作,再切换到成功状态。二维码弹窗归成功状态组件管理,页面不再保存它的开关。

业务组件管理自身行为

资料页面有一块支持自动保存的文本输入。重构过程中,这部分状态一度统一放在页面级 composable,组件只接收数据和回调。输入组件的功能没有减少,但计时器、保存状态和离开前提交都由外层管理。

我把自动保存放回输入组件。页面跳转前仍然需要等待保存,因此组件暴露 flush(),外层等待它完成后再继续。保存的内部过程留在组件中,跳转顺序由页面协调。

上传卡片也做了类似调整。原来父页面传入文件列表、上传进度,以及上传、删除、下载等回调;调整后,这些行为由卡片管理。父页面只需要文件数量来判断后续操作是否可用,就通过 v-model:files-count 同步数量。

需要由多个组件共用或协调的逻辑,仍然保留在 composable 中。图表则接收 props,由调用方从 API 或 Pinia 获取数据,避免绑定到特定页面的数据来源。

业务组件自行请求也需要检查重复加载。同一页面的几个区块都取得项目数据时,要确认缓存是否有效,或者由父级获取后共享。具体放在哪里,取决于组件之间实际共用什么。

组件的复用范围

页面私有组件放在页面自己的 components 中,相关 composable 随页面维护。出现第二个使用页面时,再检查输入、交互和样式,决定是否提取到公共目录。

直接从另一个页面的私有目录导入,会让两个页面产生依赖。如果两处只是外观接近,行为并不相同,也可以分别维护。

utils 保留格式化、映射、排序等纯函数。请求、全局状态修改和路由跳转留在业务模块中,避免一个数据转换函数同时触发页面行为。

路由决定页面布局

原来的应用入口根据路径判断页面使用哪种布局。新增页面时,除了配置路由,还要检查入口中的布局分支。

我把布局改成路由组件,使用该布局的页面放进 children。应用入口只渲染路由,页面归属直接由路由层级表达。登录等不需要公共外壳的页面放在外层。

普通页面与项目内页面分别使用布局。前者有导航和页脚,后者还需要展示项目名称,外围结构不同。公共导航继续共享,两种布局各自组织内容。

路由层级与布局职责

页脚从各个页面移到普通页面布局中,按正常文档流置底。页面增加时,不必再重复处理页脚和外围滚动区域。

后续维护

几个页面调整后,我把实际采用的约定整理成 Cursor Rules,并另外维护给团队阅读的规范文档。规范用已有页面解释职责,目录按需要创建。简单页面不必补齐 composable、utils 等空层次。

项目已经维护一年多,重构后的大半年里没有再大改这套结构,新加入的前端开发也基本能沿用。后续功能继续增加,团队成员也有变化,已有划分仍然能满足日常开发。这是我认为这次重构比较有效的实际反馈。

评论

评论加载中…

输入关键词开始搜索。

选择Enter 打开Esc 关闭CtrlK 唤起