别再手写 CRUD 了:我把 Element Plus 的工作量压缩成一份列 schema

先说说我为什么造这个轮子。

之前写 React 的时候,我最喜欢的就是 antd 的 ProComponents :ProTable 一份列 schema 下去,搜索栏、表格、分页、工具栏全出来了,ProForm 的联动和弹窗表单也是拿来就用。那段时间写中后台是真的爽------业务代码只写业务,模板代码一行不用重复。

后来换了技术栈,改用 Vue3 + Element Plus。习惯性的想找同款,然后把 npm 翻了个遍:要么是几年没维护的老仓库,要么功能只覆盖一小块(有表格没表单、有表单没布局),要么 API 设计和 ProComponents 完全对不上,用起来处处别扭。用惯了好工具,再回去手写 el-form + el-table 的复读机代码,是真的难受。

所以干脆自己动手:参照 ProComponents 的 API 心智,给 Element Plus 封装了一套 el-pro-components。React 那边验证过的设计,搬到 Vue 这边,少踩坑。今天正式发版,开源出来给同样从 React 转 Vue、或者单纯想省 CRUD 工作量的同学用。


一句话介绍

列 schema 驱动的中后台模板组件库:ProTable / ProForm / ProDescriptions / ProLayout / 弹窗抽屉表单 / 查询筛选区 / 指标卡全套,内置 valueType 渲染器和请求生命周期。一张表格的业务代码,从 200 行压到 30 行。

快速上手

bash 复制代码
npm i el-pro-components element-plus vue
ts 复制代码
// main.ts
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import 'el-pro-components/style.css'   // 组件库自己的样式,记得导入
import App from './App.vue'

createApp(App).use(ElementPlus).mount('#app')

ProTable:一份 columns,表格 + 搜索栏 + 工具栏全有了

先看最典型的场景------用户列表:

vue 复制代码
<script setup>
const columns = [
  { prop: 'id', label: 'ID', valueType: 'indexBorder', width: 64, search: false },
  { prop: 'name', label: '姓名', width: 130 },
  { prop: 'role', label: '角色', valueType: 'tag',
    valueEnum: { admin: { text: '管理员', color: 'danger' }, editor: { text: '编辑', color: 'primary' } } },
  { prop: 'amount', label: '金额', valueType: 'money', sortable: 'custom', search: false },
  { prop: 'actions', label: '操作', valueType: 'option' },
]

const request = async (params) => {
  // params: { current, pageSize, ...搜索字段 }
  const { data, total } = await fetchUsers(params)
  return { data, total }
}
</script>

<template>
  <ElProTable :columns="columns" :request="request" row-key="id" selection title="用户列表">
    <template #actions="{ row }">
      <ElButton link type="primary" @click="edit(row)">编辑</ElButton>
    </template>
  </ElProTable>
</template>

这一份代码你免费获得的东西:

  • 搜索栏 :列上不标 search: false 就自动进搜索区,valueEnum 自动变成下拉框
  • 工具栏:刷新 / 密度切换 / 列设置(可拖拽排序、固定列)/ 全屏,开箱即用
  • 请求生命周期 :分页参数自动拼装、loading、翻页回顶、persistence-key 持久化用户的列配置和页大小
  • valueType 渲染 :money 千分位、tag 按 valueEnum 上色、dateTime/status/indexBorder......不用再手写 formatter
  • 轮询 ::polling="2000",监控类页面两行配置搞定

进阶能力也都在:多级表头(children 嵌套)、树形数据、展开行、合并单元格(merge-fields)、受控数据源(data-source 替代 request)、行内编辑(见下文)。

ProForm:联动、分组、动态数组,schema 一把梭

vue 复制代码
<script setup>
const model = reactive({ name: '', type: 'a', extra: '', contacts: [{ cname: '', phone: '' }] })
const columns = [
  {
    valueType: 'group', label: '基本信息', groupProps: { collapsible: true },
    columns: [{ prop: 'name', label: '姓名', valueType: 'input',
      rules: [{ required: true, message: '请输入姓名' }] }],
  },
  { prop: 'type', label: '类型', valueType: 'radio',
    valueEnum: { a: { text: '类型A' }, b: { text: '类型B' } } },
  // 列级联动:只有类型A才显示
  { prop: 'extra', label: '附加说明', valueType: 'input',
    dependency: { dependsOn: ['type'], visible: (v) => v.type === 'a' } },
  // formList:动态增删的子表单
  { prop: 'contacts', label: '联系人', valueType: 'formList', formSpan: 24,
    children: [
      { prop: 'cname', label: '姓名', valueType: 'input' },
      { prop: 'phone', label: '电话', valueType: 'input' },
    ] },
]
const onSubmit = async (values) => { await save(values); return true }
</script>

<template>
  <ElProForm :columns="columns" :model="model" :span="8" @submit="onSubmit" />
</template>

提交/重置按钮是默认带的,校验、重置、valuesChange 事件都是内置的。跨字段的「任意子树级联」用 ElProFormDependency(作用域插槽拿依赖字段值),短信验证码输入框用 ElProFormCaptcha(自带 60s 倒计时,发送失败不进倒计时)。

弹窗 / 抽屉表单:trigger 插槽直接包住按钮

vue 复制代码
<ElProModalForm v-model:open="open" :columns="modalColumns" title="新建" :on-finish="onFinish">
  <template #trigger><ElButton type="primary">新建</ElButton></template>
</ElProModalForm>

on-finish 返回 true 自动关弹窗,返回 false 或抛错留在弹窗里继续改------「接口炸了把用户刚填的东西丢掉」这种事故不会发生。ElProDrawerForm 同款 API。

行内编辑:编辑/保存/删除按钮自动渲染

vue 复制代码
<ElProEditableTable
  :columns="editColumns" :data-source="rows" row-key="id"
  :editable="{ type: 'multiple', onSave: async (key, row) => { await save(row); return true } }"
/>
  • type: 'single':一次只编辑一行,点另一行会先保存当前行(保存失败不切换)
  • 保存前按列上的 rules 校验草稿;onSave 返回 false 行留在编辑态
  • 新增行靠 onSave 的回包拿后端主键,返回对象会合并进该行

全家福清单(v0.1.0)

分类 组件
表格 ElProTable、ElProEditableTable
表单 ElProForm、ElProStepsForm、ElProModalForm、ElProDrawerForm、ProFormGroup、ElProFormDependency、ElProFormCaptcha、ElProFieldSet
筛选 ElProQueryFilter、ElProLightFilter
展示 ElProDescriptions、ElProList、ElProCard、ElProCheckCard(Group)、ElProStatistic(Card/Group)、ElProSkeleton、ElProCardDivider
布局 ElProLayout、ElProPageContainer、ElProPageHeader、ElProFooterToolbar

工具函数也直接导出:enumToOptions / formatDate / formatFromNow / formatQuarter / getISOWeek / parseDate / formatNumber / useTable,写需求时顺手就能用。

定位与边界

说实话的版本:

  • ✅ 适合:Vue3 + Element Plus 技术栈的中后台/管理端,想省 CRUD 模板工作量
  • ✅ API 心智对齐 antd ProComponents ------columns + valueEnum + request 这套核心概念和 React 版同名同义。你在 React 项目里学过的肌肉记忆直接复用,迁移成本接近零;这也是我封它的第一原则:让「从 React 转 Vue」的同学不需要重新学一遍
  • ⚠️ 0.1.0 早期版本,API 可能还会调;文档站还在完善中,先看 GitHub README 和类型提示
  • 🚫 不打算替代 Element Plus------它是站在 EP 肩膀上的高阶封装,el-* 组件想混用随时混

最后

从 React 的 ProComponents 用到 Vue 自己封一套,中间最深的感受是:好工具的价值不只是省时间,而是让你不再容忍重复劳动。这个库还在早期,但核心链路(表格 → 表单 → 弹窗)已经在我自己的项目里跑起来了。

仓库里 README 有完整的安装说明和示例,后续会补文档站和更多 valueType。如果你也是从 React 转 Vue 的,或者这库帮你省了时间,去给个 Star 就是最大的鼓励;踩到坑欢迎提 issue,看到就修。

📖 在线文档(含示例):april-zheng.github.io/el-pro-comp... 🐙 github.com/April-Zheng... 📦 www.npmjs.com/package/el-...

相关推荐
MetWeave18 分钟前
风的三十年:一个机场的风在变小吗:10,958 天的账(《风不是一个数》系列第 6 篇)
前端·数据可视化
青烟小生21 分钟前
前端实时协同编辑与 CRDT 冲突解决实战:从 OT 到 Yjs 底层原理(完整版)
前端
陈随易23 分钟前
神级 Skill,让 AI 用 HTML 代替 Markdown 回复
前端·后端·程序员
eidnxndrdkdns31 分钟前
PE 自校验的三个坑:恒失败、基址变化、以及被漏在外面的检测器
前端
90后的晨仔35 分钟前
解决 Android 构建报错:Unable to delete file .../file-map.txt
android·前端
Yuhano40 分钟前
W4. RAG 让 Agent 拥有"外部记忆"
前端·aigc
用户308169987648543 分钟前
gzip 和 br 压同一份 JSON:7.6MB 压到 175KB,差 3.8 倍
前端
掘金者阿豪1 小时前
电商视觉要被 Agent 重做了:一个平台跑通主图、详情页、实拍、复刻和视频
前端
爱勇宝1 小时前
《道德经》第 13 章:别让评价系统控制你的心
前端·后端·产品