vue的组件拆分有什么心得
Vue 组件拆分实战心得(Vue2/Vue3 通用,从入门到企业规范)
一、先记住核心拆分原则(所有拆分的底层依据)
1. 单一职责原则(最重要)
一个组件只做一件事:
- 只负责展示 → 展示组件
- 只负责表单录入 → 表单组件
- 只负责表格列表 → 表格组件
禁止一个页面几千行代码,列表、搜索、新增弹窗、详情、编辑全写在一个
.vue里。
反例:
正例:把弹窗、搜索、表格单独抽离。
UserList.vue 包含:搜索栏、表格、分页、新增弹窗、编辑弹窗、详情弹窗、批量删除、导入导出、各种状态渲染。
2. 可复用原则:多处用到的必须抽公共组件
只要页面出现≥2 次相同 UI / 逻辑,立刻抽成公共组件:
- 通用:分页、上传、弹窗、卡片、状态标签、搜索栏、按钮组、权限按钮
- 业务:订单状态卡片、商品信息卡片、用户选择器、文件预览弹窗
3. 复杂度阈值原则(行数红线)
- 单个组件建议:≤300 行,最多不超过 500 行
- 超过直接拆分:模板太长、方法几十行、大量 v-if、复杂计算属性,优先拆子组件
- 弹窗、抽屉、复杂表单,一律单独新建组件,不要写在页面内部
4. 分层原则:页面按「页面容器 → 业务子组件 → 公共基础组件」三层拆分
- 页面级(views):只做统筹
负责:请求接口、管理全局状态、父子传参、控制弹窗显隐、分发数据,不写复杂 DOM、不封装复杂工具方法。
- 业务组件级(components/business):当前业务内复用
用户表格、角色表单、筛选区域、详情卡片,只在当前模块复用。
- 公共基础组件(components/common):全局任意页面可复用
通用弹窗、分页、图片预览、上传、空状态、权限按钮等。
5. 数据驱动原则:按「数据维度」拆分,不是按视觉位置拆分
不要凭页面上下左右拆分,要按数据归属拆分:
- 同一批接口返回的数据渲染的区域 → 可以放一个组件
- 依赖不同接口、不同状态控制的模块 → 必须拆分
例:列表页:搜索区(筛选参数)、表格区(列表数据)、操作弹窗(表单数据),三份独立数据源,天然拆 3 个组件。
二、四种经典组件拆分场景 + 最佳实践
场景 1:列表页(后台管理系统最常见)
原始大页面:搜索栏 + 表格 + 分页 + 新增 / 编辑弹窗 + 详情弹窗
推荐拆分结构:
plaintext
views/user/
├─ index.vue # 父页面(控制器)
├─ components/
├─ UserSearch.vue # 搜索筛选组件
├─ UserTable.vue # 表格+分页组件
├─ UserForm.vue # 新增、编辑共用表单弹窗
└─ UserDetail.vue # 详情抽屉/弹窗
父子职责划分(黄金分工)
- 父页面 index.vue
- 定义查询参数、列表数组、弹窗显隐标识
- 封装列表请求、新增 / 编辑 / 删除接口调用
- 通过
props向下传:查询条件、表格数据、弹窗打开状态 - 通过自定义事件
$emit接收子组件触发的搜索、新增、保存、删除等动作
- 子组件只做两件事:UI 渲染 + 事件向上派发
- 不直接发请求,不操作 Vuex 全局状态
- 只通过 props 接收数据,通过事件告诉父页面 “我要做什么操作”
核心好处:子组件高度纯净、可复用、方便单元测试、后期改 UI 只动子组件,不会污染父页面逻辑。
场景 2:复杂表单页(多步骤、多区块、超长表单)
比如:订单提交页,包含基础信息、收件地址、商品清单、发票信息、备注。
拆分思路:按业务区块拆分,共用父页面统一收集表单数据。
plaintext
views/order/create/
├─ index.vue
└─ components/
├─ BaseInfo.vue
├─ AddressSelect.vue
├─ GoodsList.vue
└─ InvoiceForm.vue
传参方案:父页面维护一个大表单对象,通过
v-model / props + emit 双向同步各子组件字段,最终统一提交。场景 3:弹窗 / 抽屉组件(高频踩坑点)
❌ 错误:弹窗直接写在父页面 template 里,v-if 控制显隐,代码堆积。
✅ 正确:弹窗单独抽组件,父页面通过布尔值控制引入、打开关闭。
优点:
- 弹窗关闭销毁组件,避免上次表单数据缓存污染
- 表单校验、字段规则封装在弹窗内部,父页面更清爽
- 同一个弹窗可以在多个按钮处复用
场景 4:全局通用 UI 组件
多处页面用到:空数据、分页、文件上传、图片预览、通用表格、封装 el-dialog。
统一放在
src/components/common,全局注册或按需引入,带默认属性、支持自定义插槽,统一 UI 规范。三、组件通信选型(拆分后配套规范,避免乱传参)
- 父子组件:优先
props向下传 + $emit向上抛事件禁止子组件直接修改 props、子组件操作父页面变量。 - 跨层级多层组件:
- Vue2:简单场景用
$attrs/$listeners;复杂全局状态(登录、权限、字典)放 Vuex - 不要多层父子层层透传参数(prop 逐级穿透),尽量抽全局状态。
- Vue2:简单场景用
- 兄弟组件:通过父页面中转,或者用 Vuex。
- 全局弹窗、全局提示类组件:挂载 Vue 原型调用(this.、confirm),不用组件引入方式。
四、目录结构拆分规范(企业通用)
plaintext
src
├─ views # 页面级组件,路由对应页面
│ ├─ user
│ │ ├─ index.vue
│ │ └─ components # 当前页面私有业务组件
│ └─ order
├─ components
│ ├─ common # 全局公共基础组件(所有页面可复用)
│ │ ├─ PagePagination
│ │ ├─ UploadFile
│ │ └─ EmptyData
│ └─ business # 业务通用组件(多个模块复用)
│ ├─ OrderCard
│ └─ UserSelect
└─ store # 全局状态,存放用户、权限、字典等全局数据
命名规范避坑
- 组件名:大驼峰
UserTable.vue,避免小写、短缩写模糊命名; - 页面内私有组件统一放在当前页面的 components 文件夹,不要和全局组件混放;
- 公共组件必须写注释、默认 props、入参校验(props 校验)。
五、拆分避坑心得(踩坑总结)
1. 不要过度拆分(拆分不是越细越好)
- 一段 UI + 逻辑只有几十行,且只在当前页面用一次,没必要强行拆组件;
- 过度拆分会导致:父子传参满天飞、业务逻辑分散、排查问题需要来回跳转多个文件,维护成本飙升。
判断要不要拆:
- 代码 > 300 行 / 多处复用 / 独立业务模块 → 拆
- 仅少量 UI 片段、只使用一次、几十行代码 → 不拆,用模板片段即可。
2. 别把业务逻辑下沉到子组件
子组件只负责 UI 展示,接口请求、权限判断、分页查询、数据处理尽量放在父页面。
如果子组件自己发请求,后期排查接口来源、统一接口拦截、权限管控会非常混乱。
3. props 一定要做类型校验
拆分后多人协作极易传错参数,必须约束类型、默认值:
js
运行
props: {
tableData: {
type: Array,
default: () => []
}
}
4. 插槽灵活预留,提升组件通用性
封装表格、弹窗、卡片类组件时,预留头部、尾部、操作列插槽,避免每次 UI 微调就要改组件源码。
5. 纯展示组件尽量做「无状态组件」
只依赖 props 渲染,内部不维护 data,不修改外部数据,可做到极致复用,方便缓存、性能优化。
六、极简拆分口诀
- 一页超三百,立刻拆组件;
- 多处重复用,抽到公共区;
- 父管接口与状态,子管渲染与事件;
- 弹窗表单单独抽,不要堆在页面里;
- 能少拆不多拆,适度分层才好维护;
- 全局状态放 Vuex,局部数据父子传参。
七、进阶优化心得
- 高度相似的组件,通过 props 配置化(type、status)来控制不同 UI,不用重复新建多个组件;
- 通用组件支持属性透传($attrs),不用每一个属性都手动定义 props;
- 复杂计算放在父页面 computed 处理,不要让多个子组件重复计算;
- 拆分同时做好组件懒加载,路由懒加载、异步组件,优化首屏性能。
需要我给一份「后台管理系统标准组件目录 + props 规范模板」吗?

浙公网安备 33010602011771号