【原创】Vue3 + Element-Plus 企业级组件库
开箱即用的表单/表格/图表一体化解决方案 | 15+ 核心组件 | 支持联动 | 高度可配置

最新更新:2026-05-26
GitHub:https://github.com/mengy822/form-table
📌 一、组件库介绍
本组件库基于 Element-Plus 和 Vue3 开发,专注于中后台管理系统的表单/表格/图表场景,提供 15+ 核心组件,支持高度自定义配置。
核心组件列表
| 组件名 |
功能说明 |
| MyForm |
搜索表单组件,支持自动换行、折叠展开、一键重置 |
| MyTable |
表格组件,支持动态列显隐、多级表头、树形数据、排序 |
| MyTableV2 |
虚拟表格组件,基于 el-table-v2,适用于大数据量场景 |
| MyDetail |
详情弹框组件,基于 el-descriptions,支持无限层级嵌套 |
| MyEdit |
编辑弹框组件,动态表单校验、自动布局、数据自动转换 |
| MyDialog |
通用弹框组件,支持 beforeClose 控制关闭 |
| MyImport |
导入组件,Excel 导入 + 错误信息展示 |
| Echarts |
图表组件,支持多图联动(图例/Tooltip/点击联动) |
辅助组件
| 组件名 |
功能说明 |
| Input |
输入框(支持 text/textarea/password/number/numberRange) |
| Select |
下拉框(支持单选/多选/分组/远程搜索) |
| Date |
日期选择(支持所有 Element-Plus 日期类型) |
| Switch |
开关 |
| Checkbox |
多选框(支持普通/按钮样式) |
| Radio |
单选框(支持普通/按钮样式) |
| File |
文件上传(支持类型/大小限制、模板下载) |
🚀 二、快速开始
安装依赖
npm install element-plus echarts
引入组件
import MyTable from '@/components/FormTable/MyTable.vue'
import MyEdit from '@/components/FormTable/MyEdit.vue'
import MyDetail from '@/components/FormTable/MyDetail.vue'
import Echarts from '@/components/FormTable/Echarts/index.vue'
📊 三、表格组件 (MyTable)
3.1 基础表格

3.2 多级表头

3.3 基础使用
<MyTable
ref="tableRef"
:table-column="tableColumns"
:data-list-fun="getList"
:data-load-fun="request"
:data-config="dataConfig"
:base-class="'.app-main'"
@add="handleAdd"
@update="handleEdit"
@detail="handleDetail"
@remove="handleDelete"
@export="handleExport"
@custom-event="handleCustomEvent"
>
<!-- 自定义状态列(插槽名与 prop 或 slot 属性值相同) -->
<template #status="{ row }">
<el-tag :type="row.status === 1 ? 'success' : 'danger'">
{{ row.status === 1 ? '启用' : '禁用' }}
</el-tag>
</template>
<!-- 操作列额外按钮 -->
<template #operationAfter="{ data, loading }">
<el-button link type="primary" :loading="loading" @click="handleCustom(data)">
重置密码
</el-button>
</template>
</MyTable>
3.4 列配置示例
const tableColumns = [
// 基础列
{ prop: 'userName', label: '用户名', width: 120, fixed: 'left' },
{ prop: 'age', label: '年龄', width: 80, align: 'center' },
// 嵌套对象(支持 a.b.c 路径)
{ prop: 'user.profile.email', label: '邮箱', width: 200 },
// 多字段组合(使用 ~ 分隔符,也支持 , - /)
{ prop: 'createTime~endTime', label: '有效期', width: 200 },
// 自定义渲染(使用 renderTxt 处理默认值)
{
prop: 'createTime',
label: '创建时间',
width: 180,
fun: (row, prop, { renderTxt }) => renderTxt(row[prop])
},
// 带单位的数值
{ prop: 'price', label: '价格', width: 100, unit: '元', decimalPlaces: 2 },
// 使用插槽自定义(通过 slot 属性指定插槽名)
{ prop: 'status', label: '状态', width: 100, slot: 'customStatus' }
]
3.5 数据加载方式
方式一:使用 dataListFun(推荐)
const getList = (params, callback) => {
callback(
new Promise((resolve) => {
fetchUserList(params).then(res => {
resolve({ rows: res.data, total: res.total })
}).catch(() => {
resolve({ rows: [], total: 0 })
})
})
)
}
方式二:直接传入 URL(需配合 dataLoadFun)
const request = (config) => {
return axios(config)
}
3.6 事件处理
// 新增
const handleAdd = () => {
editDialogRef.value?.init({})
}
// 修改(推荐格式:传入 Promise 显示加载效果)
const handleEdit = (row, callback) => {
editDialogRef.value?.init(getInfo(row.id), undefined, (e) => {
callback()
})
}
// 详情(推荐格式:传入 Promise 显示加载效果)
const handleDetail = (row, callback) => {
detailDialogRef.value?.init(getInfo(row.id), (e) => {
callback()
})
}
// 删除(callback 支持 Promise、URL 等方式)
const handleDelete = (row, callback) => {
callback(deleteUser(row.id))
// 或 callback('/api/user/delete', { id: row.id })
// 或 callback('/api/user/delete', { id: row.id }, 'DELETE')
}
// 导出
const handleExport = (exportData, callback) => {
callback('/api/export', exportData, '用户数据.xlsx', 'post')
}
3.7 主要属性
| 属性名 |
类型 |
默认值 |
说明 |
| hasPage |
Boolean |
true |
是否显示分页 |
| hasIndex |
Boolean/String |
true |
显示序号列 |
| hasSelection |
Boolean/Function |
false |
显示多选列 |
| hasOperation |
Boolean/String |
true |
显示操作列 |
| hasAdd |
Boolean/String/Function |
'新增' |
显示新增按钮 |
| hasUpdate |
Boolean/String/Function |
'修改' |
显示修改按钮 |
| hasDetail |
Boolean/String/Function |
'详情' |
显示详情按钮 |
| hasRemove |
Boolean/String/Function |
'删除' |
显示删除按钮 |
| hasExport |
Boolean/String/Function |
true |
显示导出按钮 |
| maxHeight |
Number/String |
- |
表格最大高度 |
| baseClass |
String |
'' |
基础样式类(用于自动计算高度) |
| tableColumn |
Array |
必填 |
表格列配置 |
| dataListFun |
Function |
- |
数据加载函数 |
| dataConfig |
Object |
{ rows: 'rows', total: 'total', extra: 'extra' } |
数据格式配置 |
✏️ 四、编辑弹框组件 (MyEdit)
4.1 表单多列情况 (span < desColumn)

4.2 基础使用
<MyEdit
ref="editRef"
:column="editColumns"
:label-width="'100px'"
:des-column="2"
:data-config="dataConfig"
:auto-update="refreshTable"
@submit="handleSubmit"
/>
4.3 表单配置示例
const editColumns = [
// 文本输入框(占 1/2 宽度)
{
prop: 'userName',
label: '用户名',
type: 'input',
inputType: 'text',
isRequired: true,
maxlength: 50,
span: 1
},
// 邮箱输入框(占 1/2 宽度)
{
prop: 'email',
label: '邮箱',
type: 'input',
inputType: 'text',
isRequired: true,
span: 1
},
// 日期范围(占满整行,自动拆分为两个字段)
{
label: '有效期',
prop: 'dateRange',
type: 'date',
dateType: 'daterange',
aliases: 'startDate,endDate',
isRequired: true,
span: 2
},
// 多选下拉(转为逗号字符串)
{
label: '角色',
prop: 'roles',
type: 'select',
multiple: true,
valueType: 'string',
options: [
{ label: '管理员', value: 'admin' },
{ label: '普通用户', value: 'user' }
],
span: 1
},
// 数字范围校验
{
prop: 'score',
label: '分数',
type: 'input',
inputType: 'number',
min: 0,
max: 100,
isRequired: 'numberAuto',
span: 1
}
]
const handleSubmit = (data, callback) => {
callback(saveUser(data))
}
4.4 isRequired 校验规则说明
isRequired 支持三种类型:boolean、Function、string(内置校验规则)
内置校验规则列表:
| 规则名称 |
说明 |
适用场景 |
notEmpty |
必填(自动生成字符串) |
通用必填 |
strRequired |
字符串必填 |
文本输入框 |
phone |
手机号校验 |
手机号输入框 |
idNo |
身份证校验 |
身份证号输入框 |
number |
正整数 |
年龄、数量 |
numberAuto |
数字范围校验 |
根据 min/max/decimalPlaces 限制 |
decimal |
小数两位 |
金额、价格 |
password |
密码设置 |
密码输入框 |
4.5 布局规则
desColumn 控制表单总列数(如设为 2,则每行最多 2 个表单项)
- 每个表单项的
span 控制宽度占比(如 desColumn=2,span=1 占 50%,span=2 占 100%)
- 表单项按数组顺序自动换行排列
📋 五、详情弹框组件 (MyDetail)
5.1 普通详情

5.2 嵌套详情

5.3 基础使用
<MyDetail ref="detailRef" :column="detailColumns" :des-column="2" />
5.4 详情配置示例(支持嵌套)
const detailColumns = [
// 普通字段
{ prop: 'userName', label: '用户名', span: 1 },
{ prop: 'email', label: '邮箱', span: 1 },
// 嵌套描述列表
{
prop: 'address',
label: '地址信息',
span: 2,
list: [
{ prop: 'province', label: '省份' },
{ prop: 'city', label: '城市' },
{ prop: 'district', label: '区县' },
{ prop: 'detail', label: '详细地址' }
]
},
// 多级嵌套(无限层级)
{
prop: 'company',
label: '公司信息',
span: 2,
list: [
{ prop: 'name', label: '公司名称' },
{ prop: 'phone', label: '联系电话' },
{
prop: 'contact',
label: '联系人',
list: [
{ prop: 'name', label: '姓名' },
{ prop: 'mobile', label: '手机号' }
]
}
]
}
]
📈 六、图表组件 (Echarts)
6.1 基础使用
<!-- 不开启联动 -->
<Echarts :options="chartOptions" height="350px" width="100%" />
<!-- 多图表联动(传入 chartId 即可) -->
<Echarts :chart-id="'chart-line'" :options="lineOptions" height="300px" />
<Echarts :chart-id="'chart-bar'" :options="barOptions" height="300px" />
<Echarts :chart-id="'chart-pie'" :options="pieOptions" height="300px" />
6.2 联动效果
当满足以下条件时,图表之间会自动实现联动:
- 传入
chartId(同一页面内唯一)
- 多个图表使用相同的
linkageGroup
- 同一组内至少有 2 个图表
联动效果包括:图例联动、Tooltip 联动、点击联动。
6.3 主要属性
| 属性名 |
类型 |
默认值 |
说明 |
| options |
Object |
{} |
ECharts 配置项 |
| chartId |
String |
null |
唯一标识(传入即开启联动) |
| linkageGroup |
String |
'default' |
联动组名 |
| height |
String |
'400px' |
图表高度 |
🔄 七、数据自动转换功能
| 场景 |
配置方式 |
转换结果 |
| 日期范围 |
dateType 包含 range + aliases |
拆分为多个独立字段 |
| 多选日期 |
dateType 最后一个字符为 s |
转为逗号分隔字符串 |
| 多选下拉 |
multiple: true + valueType: 'string' |
转为逗号分隔字符串 |
| 多选复选框 |
valueType: 'string' |
转为逗号分隔字符串 |
📦 八、子组件说明
所有表单子组件支持以下公共属性:
| 属性名 |
类型 |
默认值 |
说明 |
| prop |
String |
必填 |
字段名 |
| label |
String |
必填 |
标签文本 |
| type |
String |
必填 |
组件类型 |
| isRequired |
Boolean/Function/String |
false |
是否必填 |
| isDefault |
Boolean |
false |
是否有默认值 |
| disabled |
Boolean |
false |
是否禁用 |
| clearable |
Boolean |
true |
是否可清空 |
❓ 九、常见问题
Q1:图表联动不生效?
- 确保传入
chartId,且同一组内至少有 2 个图表实例
Q2:表格高度不自适应?
- 设置
baseClass 属性,指定需要计算高度的容器选择器
Q3:如何自定义表格列内容?
- 使用插槽,插槽名与
prop 或 slot 属性值相同即可
Q4:删除/搜索事件如何直接传入 URL?
- 配置
dataLoadFun 属性,callback 参数约定:(url, params, method)
Q5:接口返回格式与默认不一致怎么办?
- 表格组件配置
dataConfig 映射 rows、total 字段
- 编辑/详情组件配置
dataConfig 映射 data、status、code 字段
📎 十、完整代码
所有组件源码、类型定义、使用示例请前往 GitHub 查看:
👉 github
👉 csdn
👉 读书成诗论坛
github
csdn
读书成诗论坛
免责声明:本组件库仅供学习交流使用,请勿用于非法用途。
如果对您有帮助,欢迎评分收藏! 👍