换框架不重写表单:vue-vben-admin 的组件设计与复用思路
【免费下载链接】vue-vben-adminA modern vue admin panel built with Vue3, Shadcn UI, Vite, TypeScript, and Monorepo. It's fast!项目地址: https://gitcode.com/GitHub_Trending/vu/vue-vben-admin
给后台写用户管理页,第一步通常是搭表单:用户名、部门、角色、头像上传。页面跑通后需求又变了——这次要把 UI 库从 Ant Design 换成 Element Plus。你打开表单文件,发现组件 props、校验规则、值处理逻辑全缠在模板里,改一个字段要翻几百行代码。
这就是 vue-vben-admin 组件设计最先要解决的问题:表单逻辑别写死在组件里,UI 框架也别当硬依赖。它的做法是四层分层、schema 驱动的表单、用 API 对象代替层层传 props。下面逐个拆开看。
想换 UI 框架,组件逻辑怎么保住
直接看仓库的目录结构,分层是物理性的,不靠约定:
| 层级 | 路径 | 放什么 |
|---|---|---|
| 原子组件层 | packages/@core/ui-kit/ | shadcn-ui 原子组件、form-ui、popup-ui、layout-ui,不依赖任何 UI 库 |
| 业务组件层 | packages/effects/common-ui/src/ | Page、验证码、图标选择器等开箱即用的组合件 |
| 布局能力层 | packages/effects/layouts/src/ | 侧边栏、页头、页签、锁屏、通知 |
| 应用层 | apps/web-antd/、apps/web-ele/等 | 每个 UI 框架一个独立 app,各写各的适配 |
关键在packages/@core/不依赖 antd 或 element-plus,而apps/下的 web-antd、web-ele、web-naive 各自只依赖一套框架,共享下面三层。所以"换框架"不是重写业务,而是多维护一个适配层。playground/则是功能最全的演示 app,写新组件时可以照着它验证多框架行为是否一致。
样式命名空间怎么做,才不会互相污染
几十个组件、五个 app 同时构建,手写全局 class 名迟早撞车。项目把类名生成收口在一个 composable 里,packages/@core/composables/src/use-namespace.ts:
const _bem = (namespace, block, blockSuffix, element, modifier) => { let cls = `${namespace}-${block}`; if (blockSuffix) cls += `-${blockSuffix}`; if (element) cls += `__${element}`; if (modifier) cls += `--${modifier}`; return cls; };组件里只写const ns = useNamespace('modal'),然后ns.b('header')、ns.e('close')、ns.m('fullscreen')、ns.is('active', open)按需取。它还提供cssVar(),把--vben-xxx形式的 CSS 变量名也一起收编。类名带统一前缀加 BEM 结构,作用域冲突基本被挡在写代码阶段。
表单越写越乱,逻辑往哪放
packages/@core/ui-kit/form-ui/里的表单是 schema 驱动的:组件不画字段,画你给的配置。看playground/src/views/examples/form/basic.vue的写法:
const [Form, formApi] = useVbenForm({ handleSubmit: onSubmit, schema: [ { component: 'Input', fieldName: 'username', label: '用户名', rules: 'required' }, { component: 'Select', fieldName: 'dept', label: '部门' }, ], wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3', });这段配置同时决定了渲染和校验,UI 文件里只剩一个<Form />。三个值得抄的设计:
- 校验规则即配置。
rules: 'required'是快捷写法,映射到form-ui/src/rule-registry.ts注册的规则;复杂场景直接传 zod schema,校验与类型共用一份定义。 - 值的编解码分离。表单内部值可以是 Dayjs、UploadFile 数组,接口要的是字符串。
useVbenForm支持codec: { encode, decode },提交前把日期格式化成字符串、回填时再还原,业务代码不用到处写转换。 - 命令式 API 外置。取值、设值、提交走
formApi.getValues()、setValues()、validateAndSubmit(),表单渲染和表单状态解耦,父组件拿不到 DOM 也能操作表单。
弹窗和表单怎么组合,不用层层传 props
后台最高频的组合就是"弹窗里放表单"。旧做法是父组件ref住弹窗、ref住表单,再手动同步显隐和值。vben 的useVbenModal用provide/inject把 API 传下去,参考playground/src/views/examples/modal/form-modal-demo.vue:
const [Modal, modalApi] = useVbenModal({ onConfirm: async () => { await formApi.validateAndSubmit(); }, onOpenChange(isOpen: boolean) { if (isOpen && modalApi.getData()?.values) { formApi.setValues(modalApi.getData().values); } }, });模板里就是<Modal><Form /></Modal>两行。弹窗通过getData()/setData()携带业务数据,lock()在提交期间禁用重复点击。子组件不接收任何 prop,连接关系在useVbenModal内部经connectedComponent建立,加字段、改标题都只动配置,不动组件树。
组件会不会变慢,怎么提前知道
复用组件的隐患是"没人敢动它"。packages/@core/ui-kit/form-ui/__tests__/下有 13 个测试文件,除了行为测试,还有form-performance.benchmark.ts这类基准测试,专门盯着表单渲染和 API 调用的耗时。改公共组件前先跑一遍测试目录,性能回归在合并前就能暴露,而不是等线上用户抱怨。
落地检查清单
- 新组件的渲染配置与逻辑拆进 schema 或 composable,UI 文件不超过约 300 行
- 类名与 CSS 变量全部经
useNamespace生成,无手写全局 class - 表单值校验走 rules/zod,值的编解码集中在 codec,不散落在业务代码
- 弹窗、表单等组合通过 api 对象 + provide/inject 连接,无 prop 深传
- 改公共组件前跑过对应
__tests__/,基准测试无回归
【免费下载链接】vue-vben-adminA modern vue admin panel built with Vue3, Shadcn UI, Vite, TypeScript, and Monorepo. It's fast!项目地址: https://gitcode.com/GitHub_Trending/vu/vue-vben-admin
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考