🪜 写在前面
在前端开发中,组件是最小的交互单元,也是系统构建的基石。 架构师如果不能设计出一套“可维护 + 可插拔 + 可复用 + 可测试”的组件体系,项目的复杂度会以指数级增长。
这一篇,我们将深入解析高质量组件设计的三大核心模式,并通过多个实战案例拆解:
- 可复用(Reusable)
- 可扩展(Extensible)
- 可插拔(Pluggable)
🧱 一、可复用组件设计:让你的组件不止用一次
✅ 原则1:数据驱动优先,props 替代硬编码
❌ 不可复用组件(写死 UI,一梭子就是干!新手必备哈哈😄)
<!-- Bad: Modal.vue -->
<template>
<div class="modal">
<h3>确认删除?</h3>
<p>删除后不可恢复</p>
<button @click="confirm">确定</button>
</div>
</template>
✅ 改造后(props 控制内容, 经典常用)
<!-- Good: Modal.vue -->
<template>
<div class="modal">
<h3>{{ title }}</h3>
<p>{{ description }}</p>
<slot name="footer">
<button @click="onConfirm">确定</button>
</slot>
</div>
</template>
<script setup>
defineProps({
title: String,
description: String,
onConfirm: Function,
})
</script>
使用方式:
<Modal title="确认删除" description="删除后不可恢复" :onConfirm="deleteUser">
<template #footer>
<pf-button type="danger" @click="deleteUser">确认删除</pf-button>
</template>
</Modal>
🔁 二、可扩展组件设计:对变化保持开放
💡 目标:当业务需求变化时,组件不被迫大改,而是通过扩展点实现新增功能。
✅ 方法1:暴露 slot 插槽(常用方式)
<!-- DataTable.vue -->
<template>
<table>
<thead>
<tr>
<th v-for="col in columns">{{ col.label }}</th>
</tr>
</thead>
<tbody>
<tr v-for="row in data">
<td v-for="col in columns">
<slot :name="col.prop" :row="row">
{{ row[col.prop] }}
</slot>
</td>
</tr>
</tbody>
</table>
</template>
使用方式:
<DataTable :columns="[{ prop: 'name', label: '名称' }]">
<template #name="{ row }">
<span style="color: red">{{ row.name }}</span>
</template>
</DataTable>
🎯 优势:
- 默认渲染走组件内逻辑
- 业务方可插入任意结构,无需修改组件源码
✅ 方法2:组件内部暴露“扩展点 API”(好用)
// useTable.ts
export function useTable({ fetchFn, transformFn }) {
const loading = ref(false)
const data = ref([])
async function load() {
loading.value = true
const res = await fetchFn()
data.value = transformFn ? transformFn(res) : res
loading.value = false
}
onMounted(load)
return { data, loading, reload: load }
}
外部传入扩展逻辑:
const { data, loading } = useTable({
fetchFn: fetchUserList,
transformFn: (res) => res.map((i) => ({ ...i, label: i.name })),
})
✅ 组件变得更加灵活、组合性更强。
🧩 三、可插拔组件设计:打造“系统级能力”
让业务开发者不改动代码,只配置/注入,即可使用组件新能力。
✅ 示例1:按钮 + 权限系统(好用)
<!-- PermissionButton.vue -->
<template>
<slot v-if="hasPermission"></slot>
</template>
<script setup>
import { usePermission } from '@/shared/hooks/usePermission'
const props = defineProps({ code: String })
const hasPermission = usePermission(props.code)
</script>
使用方式:
<PermissionButton code="user.delete">
<button @click="deleteUser">删除用户</button>
</PermissionButton>
📌 组件“无侵入”支持权限逻辑,支持任意业务接入。
✅ 示例2:动态组件注册机制(平台化组件)
// registerComponents.ts
import { app } from 'vue'
import ChartCard from './ChartCard.vue'
import TableCard from './TableCard.vue'
export const registerDynamicComponents = (app) => {
app.component('ChartCard', ChartCard)
app.component('TableCard', TableCard)
}
平台配置:
[
{ "type": "ChartCard", "data": { "title": "访客趋势" } },
{ "type": "TableCard", "data": { "columns": [...], "data": [...] } }
]
渲染引擎:
<component
v-for="item in configList"
:key="item.type"
:is="item.type"
v-bind="item.data"
/>
🎯 用户只需配置 JSON,即可渲染页面。
🧱 四、组件设计规范建议表
| 项目 | 建议 |
|---|---|
| 命名规范 | 统一 PascalCase,如 UserCard |
| props 设计 | 支持 default、可组合、类型明确 |
| 插槽设计 | 命名清晰:#header、#footer、#cell-{column} |
| 事件命名 | 使用 update:、onXXX 标准 |
| 代码拆分 | 分离逻辑 hooks、展示 UI、样式模块 |
| 性能优化 | v-memo、defineOptions({ inheritAttrs: false }) |
✅ 五、实战组件封装案例建议
- 🚀 通用弹窗服务(useDialog + Modal 插槽)
- 🧾 表格系统封装(动态列配置 + 权限按钮 + 嵌套子表格)
- 📦 上传系统(支持文件/图片/压缩包 + 自定义校验 + 后缀限制)
- 🎨 表单系统(JSON Schema 驱动 + 自定义校验规则 + 动态联动)
- 📊 图表系统(ECharts 容器 + 响应式封装 + 动态配置渲染)
🧠 总结一句话
组件不是“能用”就行,而是“能复用、能扩展、能插拔”才算架构师级别。
下一篇我们将进入工程体系能力提升阶段: 👉 《从零配置到高可控:构建你的前端脚手架》