z-crud-table
v0.0.63
Published
A powerful and flexible CRUD table component for Vue 3 and Element Plus.
Maintainers
Readme
CrudTable - 基于 Vue 3 和 Element Plus 的高级 CRUD 组件
CrudTable 是一个功能全面、高度可定制的 CRUD 表格组件,旨在通过声明式的方式,极大地简化数据驱动的页面开发。它封装了常见的增、删、改、查、分页、批量操作等逻辑,让开发者能更专注于业务本身。
✨ 功能特性
- API驱动: 通过 props 传入 URL 字符串,组件内置
axios请求逻辑。 - 高度可定制: 提供丰富的插槽,用于自定义查询条件、表格列、操作按钮等。
- 配置驱动表单: 支持通过 JSON 数组配置动态渲染新增/编辑弹窗内的表单。
- 完整的
el-table功能: 继承el-table所有原生属性和事件,无缝衔接现有使用习惯。 - 强大的生命周期: 提供完整的
onBefore和onAfter钩子,方便在操作前后进行数据处理和逻辑注入。 - 灵活的列控制: 可通过 props 单独控制多选框、序号列、操作列以及编辑/删除按钮的显示与隐藏。
- 开箱即用: 内置了分页、单行删除、批量删除等常用功能。
📦 安装
npm install your-crud-table-package-name
🚀 快速上手
在您的 Vue 组件中使用 CrudTable。
<template>
<crud-table
ref="crudTableRef"
:api-url-query="'/api/users'"
:api-url-detail="'/api/users/detail'"
:api-url-create="'/api/users'"
:api-url-update="'/api/users'"
:api-url-delete="'/api/users'"
:initial-search-form="{ pageNum: 1, pageSize: 5 }"
:dialog-form-config="dialogFormConfig"
>
<el-table-column prop="name" label="姓名" />
<el-table-column prop="email" label="邮箱" />
</crud-table>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import CrudTable from 'your-crud-table-package-name';
const crudTableRef = ref(null);
const dialogFormConfig = ref([
{ type: 'input', prop: 'name', label: '姓名' },
{ type: 'input', prop: 'email', label: '邮箱' },
]);
</script>
API 文档
属性 (Props)
| 属性名 | 描述 | 类型 | 是否必需 | 默认值 |
| --- | --- | --- | --- | --- |
| API 配置 | | | | |
| apiUrlQuery | 获取表格列表数据的接口地址。 | String | true | - |
| apiUrlDetail | 获取单条数据详情的接口地址(用于编辑时回填表单)。 | String | true | - |
| apiUrlCreate | 创建新条目的接口地址。 | String | true | - |
| apiUrlUpdate | 更新条目的接口地址。 | String | true | - |
| apiUrlDelete | 删除条目的接口地址。 | String | true | - |
| 功能控制 | | | | |
| showSelectionColumn | 是否显示表格的多选框列。 | Boolean | false | true |
| showIndexColumn | 是否显示表格的序号列。 | Boolean | false | true |
| showActionsColumn | 是否显示操作列。 | Boolean | false | true |
| showEditButton | 是否在操作列中显示默认的“编辑”按钮。 | Boolean | false | true |
| showDeleteButton | 是否在操作列中显示默认的“删除”按钮。 | Boolean | false | true |
| actionsColumnWidth | 操作列的宽度。 | Number | false | 120 |
| 表单与弹窗 | | | | |
| dialogWidth | 新增/编辑弹窗的宽度。 | String | false | '50%' |
| dialogFormConfig | 动态表单配置数组,用于快速生成弹窗内的表单。 | Array | false | [] |
| dialogFormRules | 弹窗表单的 Element Plus 验证规则。 | Object | false | {} |
| 分页配置 | | | | |
| initialSearchForm | 查询表单的初始值,包含初始分页参数 pageNum 和 pageSize。 | Object | false | { pageNum: 1, pageSize: 10 } |
| showPagination | 是否显示分页组件。 | Boolean | false | true |
| pageSizes | 每页显示个数选择器的选项设置。 | Array | false | [10, 20, 50, 100] |
| paginationLayout | 分页组件布局。 | String | false | 'total, sizes, prev, pager, next, jumper' |
| paginationBackground | 是否为分页按钮添加背景色。 | Boolean | false | true |
| paginationSmall | 是否使用小型分页样式。 | Boolean | false | false |
| paginationHideOnSinglePage | 只有一页时是否隐藏分页。 | Boolean | false | false |
| 生命周期钩子 | | | | |
| onBeforeQuery | 查询请求前执行。可用于修改请求参数。必须返回处理后的参数对象。 | Function | false | - |
| onAfterQuery | 查询请求后执行。可用于格式化返回的列表数据。必须返回处理后的数据数组。 | Function | false | - |
| onBeforeOpenDialog | 打开弹窗前执行。可用于预处理表单数据。 | Function | false | - |
| onAfterOpenDialog | 打开弹窗后执行。可用于在弹窗渲染后执行某些操作。 | Function | false | - |
| onBeforeSubmit | 表单提交前执行。可用于序列化提交的数据。必须返回处理后的数据对象。 | Function | false | - |
| onAfterSubmit | 表单提交后执行。可用于执行提交成功后的副作用。 | Function | false | - |
| onBeforeDelete | 删除操作前执行。可用于进行额外的确认。返回 false 可中止删除。 | Function | false | - |
| onAfterDelete | 删除操作后执行。可用于执行删除成功后的副作用。 | Function | false | - |
插槽 (Slots)
| 插槽名称 | 作用域 (Props) | 描述 |
| --- | --- | --- |
| default | - | (核心) 用于定义表格的列 (<el-table-column>),除了序号列、复选框列和操作列。 |
| header | - | 在整个组件最顶部插入内容,如页面大标题。 |
| query-conditions | { searchForm } | 自定义查询区域的表单项。searchForm 是响应式的查询对象。 |
| query-left | - | 在“搜索”按钮左侧添加自定义按钮或内容。 |
| query-right | - | 在“清空”按钮右侧添加自定义按钮或内容。 |
| action-left | { selections } | 在“新增”按钮左侧添加自定义按钮,可通过 selections 访问当前勾选的数据。 |
| action-right | - | 在“新增”按钮右侧添加自定义按钮。 |
| actions | { row } | (重要) 自定义操作列的内容,可用于添加、修改或完全替换默认的编辑/删除按钮。 |
| dialog-form-content | { formData, mode } | 完全自定义新增/编辑弹窗的表单内容。如果使用此插槽,dialogFormConfig 将被忽略。 |
事件 (Events)
| 事件名称 | 载荷 (Payload) | 描述 |
| --- | --- | --- |
| @open-dialog | { mode: string, data: object } | 在新增或编辑弹窗打开后触发。 |
| @submit | { mode: string, data: object } | 在表单提交(新增或更新)成功后触发。 |
| @delete | number[] | 在删除操作成功后触发,载荷为被删除的 ID 数组。 |
暴露的方法 (Exposed Methods)
通过 ref 可以获取到组件实例,并调用其暴露的方法。
| 方法名称 | 参数 | 描述 |
| --- | --- | --- |
| refresh() | - | 强制刷新表格数据,使用当前的查询条件和分页状态。 |
| search() | - | 重置到第一页并刷新数据,相当于点击“搜索”按钮。 |
| handleDelete(ids: number[]) | ids (ID 数组) | 触发删除操作,可用于父组件中自定义的批量删除逻辑。 |
| openDialog(mode, data) | mode, data | 手动打开新增/编辑弹窗。 |
实践案例
<template>
<crud-table
ref="crudTableRef"
:api-url-query="'/api/users'"
:api-url-detail="'/api/users/detail'"
:api-url-create="'/api/users'"
:api-url-update="'/api/users'"
:api-url-delete="'/api/users'"
:show-delete-button="false"
actions-column-width="140"
:initial-search-form="{ role: null, pageNum: 1, pageSize: 5 }"
@submit="onSubmit"
:on-after-query="handleAfterQuery"
>
<template #header>
<h2 class="text-2xl font-semibold text-slate-700 mb-6">用户管理</h2>
</template>
<el-table-column prop="name" label="姓名" sortable />
<el-table-column prop="role" label="角色">
<template #default="scope">
<el-tag :type="scope.row.role === 'admin' ? 'warning' : 'info'">
{{ scope.row.role }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="createdAtFormatted" label="创建时间" />
<template #query-conditions="{ searchForm }">
<el-form-item label="姓名">
<el-input v-model="searchForm.name" clearable />
</el-form-item>
</template>
<template #actions="{ row }">
<el-button size="small" type="primary" link @click="crudTableRef?.openDialog('edit', row)">编辑</el-button>
<el-button size="small" type="success" link @click="handleViewDetails(row)">详情</el-button>
</template>
</crud-table>
</template>
<script setup>
import { ref } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import CrudTable from './components/CrudTable.vue';
const crudTableRef = ref(null);
// 使用生命周期钩子格式化数据
const handleAfterQuery = (data) => {
return data.map(item => ({
...item,
createdAtFormatted: new Date(item.createdAt).toLocaleString('zh-CN'),
}));
};
// 监听事件
const onSubmit = (payload) => {
ElMessage.success(`[Event] ${payload.mode} success!`);
};
// 自定义方法
const handleViewDetails = (row) => {
ElMessageBox.alert(JSON.stringify(row, null, 2), '详情');
};
</script>