参数属性配置
| 属性 | 说明 | 类型 | 默认 |
|---|---|---|---|
| columnIndex | 是否显示行号 | bool | false |
| ck | 是否显示复选框checkbox | bool | true |
| loadKey | 是否自动绑定数据源 | bool | true |
| single | 表格是否单选 | bool | false |
| textInline | 表格文本超出时不换行显示 | bool | true |
| paginationHide | 隐藏分页 | bool | true |
| defaultLoadPage | 是否默认加载表格数据 | bool | true |
| url | 加载表数据接口,见下面绑定接口+跨页选择 | string | |
| tableData | 表格数据(注意使用时必须不能直接tableData=[值],正确用法tableData.splice(0);tableData.push(...[数据])) | array | [] |
| rowKey | 树形结构的主键字段,如果设置值默认会开启树形table;注意rowKey字段的值必须是唯一,具体使用见【树形结构】示例 | string | |
| rowParentField | 树形结构的主键字段的父级id,具体使用见【树形结构】示例 | string | |
| loadTreeChildren | 树形结构加载子节点方法,具体使用见【树形结构】示例 | function | |
| lazy | 树形表格是否延迟加载,具体使用见【树形结构】示例 | bool | true |
| defaultExpandAll | 树形表格是否展开所有节点,具体使用见【树形结构】示例 | bool | false |
| expandRowKeys | 树形表格默认展开的节点,具体使用见【树形结构】示例 | array | [] |
| beginEdit | 表格行进入编辑前方法,见上面【表格编辑】示例:beginEdit(row, column, index){ return true} | function | |
| endEditBefore | 表格行结束前编辑方法,见上面【表格编辑】示例:endEditBefore(row, column, index){ return true} | function | |
| endEditAfter | 表格行结束编辑后方法,见上面【表格编辑】示例:endEditAfter(row, column, index){ return true} | function | |
| pagination | 分页信息:{sort: ""//排序字段,order: "desc"//排序方式desc/asc,total: 0//总行数,sizes: [30, 60, 100, 120]//分页信息,size: 30, // 默认分页大小 wheres: []//查询条件, page: 1//分页大小} | json | {} |
| height | 表格高度见下面表格设置height高度属性计算示例 | int | 0 |
| select2Count | 表格下拉框最大显示数量(超出后自动转换为select2组件) | int | 1500 |
| selectable | 复选框是否可以选中,见【基础表格+事件处理】示例:selectable(row, index){return true} | function | |
| highlightCurrentRow | 是否高亮显示当前选中行 | bool | true |
| dragPosition | 表格是否可拖动改变大小,见【基础表格+事件处理】:顶部拖动top,底部bottom | string | |
| spanMethod | 合并单元格,示例见:表单+查询+合并单元格 | function | |
| reserveSelection | 分页或者刷新表格数据后是否保留复选框选择状态(跨页选择数据),见:绑定接口+跨页选择 | bool | false |
| sortable | 表格是否可以拖动排序数据,见【基础表格+事件处理】示例 | bool | false |
| pagerCount | 分页按钮显示最大数量 | int | 7 |
| columns | 表格字段配置,见下面表格columns | Array | [] |
1.支持数据绑定、行内编辑、分页、排序、筛选、合计、树形结构、拖拽排序、多级表头、跨页选择、自定义渲染等功能

组件概述
vol-table 是一个功能强大的表格组件,基于 Element Plus 的 el-table 和 el-table-v2 封装,提供了丰富的表格功能和便捷的配置方式。
主要特性
- 数据绑定: 支持通过
url接口自动加载数据,或通过tableData手动绑定数据 - 行内编辑: 支持点击行进入编辑模式,支持多种编辑类型(输入框、下拉框、日期选择器、文件上传等)
- 分页功能: 内置分页组件,支持自定义分页大小和分页信息
- 排序筛选: 支持列排序和表头筛选功能
- 合计功能: 支持列合计,可自定义合计格式
- 树形结构: 支持树形表格展示,支持懒加载和展开控制
- 拖拽排序: 支持表格行拖拽排序
- 多级表头: 支持多级表头配置
- 跨页选择: 支持跨分页选择数据,保留选择状态
- 高性能模式: 支持
tableV2高性能表格模式,适用于大数据量场景 - 自定义渲染: 支持通过
render函数自定义单元格内容 - 固定列: 支持左侧或右侧固定列
- 单元格合并: 支持自定义单元格合并规则
查看代码
基础使用
<template>
<div class="table-item">
<div class="table-item-header">
<vol-title icon="edit" title="基础表格"></vol-title>
<div class="table-item-buttons">
<el-button type="primary" @click="addRow" plain>添加行</el-button>
<el-button type="primary" @click="delRow" color="#f89898" plain>删除行</el-button>
<el-button type="primary" @click="getSelected" plain>获取选中行</el-button>
<el-button type="primary" @click="reload" color="#95d475" plain>刷新</el-button>
</div>
</div>
<!--
ck: 显示复选框
column-index: 显示行号
url: 数据接口地址(可选,也可以使用 tableData 手动绑定数据)
columns: 表格列配置
max-height: 表格最大高度
pagination-hide: 是否隐藏分页
load-key: 是否自动加载字典数据源
-->
<vol-table
ref="tableRef"
ck
column-index
:url="url"
:columns="columns"
:max-height="maxHeight"
:pagination-hide="false"
:load-key="true"
@loadBefore="loadBefore"
@loadAfter="loadAfter"
@rowClick="rowClick"
@rowDbClick="rowDbClick"
@selectionChange="selectionChange"
></vol-table>
</div>
</template>
<script lang="jsx" setup>
import VolTable from "@/components/basic/VolTable.vue";
import { ref, reactive, getCurrentInstance } from "vue";
const { proxy } = getCurrentInstance();
const tableRef = ref();
// 计算表格高度
const maxHeight = ref(0);
maxHeight.value = document.body.clientHeight - 250;
// 数据接口地址(可选)
const url = ref("api/Demo_Order/getPageData");
// 表格数据加载前处理
const loadBefore = (params, callBack) => {
// 可以在这里添加查询条件
// params.wheres.push({
// name: "OrderNo",
// value: orderNo.value,
// displayType: "like"
// });
callBack(true); // true 表示继续加载,false 表示取消加载
};
// 表格数据加载后处理
const loadAfter = (rows, callBack, result) => {
// 可以对加载后的数据进行处理
callBack(true);
};
// 行点击事件
const rowClick = ({ row, column, event, index }) => {
console.log("点击了第", index, "行", row);
};
// 行双击事件
const rowDbClick = ({ row, column, event, index }) => {
console.log("双击了第", index, "行", row);
};
// 复选框选择事件
const selectionChange = (rows) => {
console.log("选中的行:", rows);
};
// 添加行
const addRow = () => {
tableRef.value.addRow({ OrderNo: "D2022040600009" });
};
// 删除行
const delRow = () => {
tableRef.value.delRow();
proxy.$message.success("删除成功");
};
// 获取选中行
const getSelected = () => {
const rows = tableRef.value.getSelected();
if (!rows.length) {
proxy.$message.error("请选中行");
return;
}
proxy.$message.success(JSON.stringify(rows));
};
// 刷新表格
const reload = () => {
tableRef.value.load();
proxy.$message.success("刷新成功");
};
// 表格列配置
const columns = reactive([
{
field: "OrderNo",
title: "订单编号",
type: "string",
width: 130,
align: "center",
fixed: true, // 固定列
filterData: true, // 开启筛选
showOverflowTooltip: true, // 内容超出时显示提示
},
{
field: "OrderType",
title: "订单类型",
type: "int",
bind: { key: "订单类型", data: [] }, // 绑定字典数据源
width: 100,
},
{
field: "TotalPrice",
title: "总价",
type: "decimal",
width: 100,
align: "right",
summary: true, // 开启合计
sort: true, // 开启排序
},
{
field: "OrderDate",
title: "订单日期",
type: "date",
width: 120,
},
{
field: "CreateDate",
title: "创建时间",
type: "datetime",
width: 160,
},
]);
</script>
<style lang="less" scoped>
.table-item-header {
display: flex;
padding: 6px 0;
.table-item-buttons {
margin-left: auto;
}
}
</style>
手动绑定数据
<template>
<div class="table-item">
<div class="table-item-header">
<vol-title icon="edit" title="手动绑定数据"></vol-title>
<div class="table-item-buttons">
<el-button type="primary" @click="addRow" plain>添加行</el-button>
<el-button type="primary" @click="delRow" color="#f89898" plain>删除行</el-button>
</div>
</div>
<!-- 使用 tableData 手动绑定数据,不使用 url -->
<vol-table
ref="tableRef"
ck
column-index
:table-data="tableData"
:columns="columns"
:max-height="maxHeight"
:pagination-hide="true"
></vol-table>
</div>
</template>
<script lang="jsx" setup>
import VolTable from "@/components/basic/VolTable.vue";
import { ref, reactive } from "vue";
const tableRef = ref();
const maxHeight = ref(document.body.clientHeight - 236);
// 手动绑定的表格数据
const tableData = reactive([
{
OrderNo: "D2023082400001",
OrderType: 3,
TotalPrice: 180,
OrderDate: "2023-08-09",
CreateDate: "2023-08-24 00:52:52",
},
{
OrderNo: "D2023082400002",
OrderType: 2,
TotalPrice: 200,
OrderDate: "2023-08-10",
CreateDate: "2023-08-24 01:52:52",
},
]);
// 添加行(注意:不能直接 tableData = [],需要使用 splice 和 push)
const addRow = () => {
tableRef.value.addRow({
OrderNo: "D2023082400003",
OrderType: 1,
TotalPrice: 150,
OrderDate: "2023-08-11",
CreateDate: new Date().toLocaleString(),
});
};
// 删除行
const delRow = () => {
tableRef.value.delRow();
};
// 表格列配置
const columns = reactive([
{ field: "OrderNo", title: "订单编号", type: "string", width: 130 },
{ field: "OrderType", title: "订单类型", type: "int", width: 100 },
{ field: "TotalPrice", title: "总价", type: "decimal", width: 100 },
{ field: "OrderDate", title: "订单日期", type: "date", width: 120 },
{ field: "CreateDate", title: "创建时间", type: "datetime", width: 160 },
]);
</script>
行内编辑
<template>
<div class="table-item">
<div class="table-item-header">
<vol-title icon="edit" title="行内编辑"></vol-title>
<div class="table-item-buttons">
<el-button type="primary" @click="validate" plain>验证表格</el-button>
<el-button type="primary" @click="getTableData" plain>获取表格数据</el-button>
</div>
</div>
<!--
beginEdit: 进入编辑前的回调
endEditBefore: 结束编辑前的回调
-->
<vol-table
ref="tableRef"
:url="url"
:columns="columns"
:max-height="maxHeight"
:pagination-hide="false"
:load-key="true"
:beginEdit="beginEdit"
:endEditBefore="endEditBefore"
></vol-table>
</div>
</template>
<script lang="jsx" setup>
import VolTable from "@/components/basic/VolTable.vue";
import { ref, reactive, getCurrentInstance } from "vue";
const { proxy } = getCurrentInstance();
const tableRef = ref();
const maxHeight = ref(document.body.clientHeight - 250);
const url = ref("api/Demo_Order/getPageData");
// 进入编辑前的回调
const beginEdit = (row, column, index) => {
console.log("进入编辑", row, column, index);
return true; // 返回 true 允许编辑,false 禁止编辑
};
// 结束编辑前的回调
const endEditBefore = (row, column, index) => {
console.log("结束编辑前", row, column, index);
// 可以在这里进行数据验证
if (column.field === "TotalPrice" && row.TotalPrice < 0) {
proxy.$message.error("总价不能小于0");
return false; // 返回 false 阻止结束编辑
}
return true;
};
// 验证表格数据
const validate = () => {
tableRef.value.validate((valid) => {
if (valid) {
proxy.$message.success("验证通过");
} else {
proxy.$message.error("验证失败:" + proxy.errMsg);
}
});
};
// 获取表格数据
const getTableData = () => {
const data = tableRef.value.getTableData();
console.log("表格数据:", data);
proxy.$message.success("数据已输出到控制台");
};
// 表格列配置(带编辑功能)
const columns = reactive([
{
field: "OrderNo",
title: "订单编号",
type: "string",
width: 130,
edit: { type: "input" }, // 输入框编辑
required: true, // 必填
},
{
field: "OrderType",
title: "订单类型",
type: "int",
width: 100,
bind: { key: "订单类型", data: [] },
edit: { type: "select" }, // 下拉框编辑
},
{
field: "TotalPrice",
title: "总价",
type: "decimal",
width: 100,
edit: { type: "decimal" }, // 数字输入框
min: 0, // 最小值
},
{
field: "OrderDate",
title: "订单日期",
type: "date",
width: 120,
edit: { type: "date" }, // 日期选择器
},
{
field: "Remark",
title: "备注",
type: "string",
width: 200,
edit: { type: "textarea" }, // 文本域
},
]);
</script>
高性能表格
<template>
<div class="table-item">
<div class="table-item-header">
<vol-title icon="edit" title="高性能表格"></vol-title>
</div>
<!--
table-v2: 启用高性能表格模式(适用于大数据量场景)
row-height: 行高度
-->
<vol-table
ref="tableRef"
:table-v2="true"
:row-height="37"
:url="url"
:columns="columns"
:max-height="maxHeight"
:pagination-hide="false"
:load-key="true"
></vol-table>
</div>
</template>
<script lang="jsx" setup>
import VolTable from "@/components/basic/VolTable.vue";
import { ref, reactive } from "vue";
const tableRef = ref();
const maxHeight = ref(document.body.clientHeight - 250);
const url = ref("api/Demo_Order/getPageData");
// 表格列配置
const columns = reactive([
{ field: "OrderNo", title: "订单编号", type: "string", width: 130 },
{ field: "OrderType", title: "订单类型", type: "int", width: 100 },
{ field: "TotalPrice", title: "总价", type: "decimal", width: 100 },
{ field: "OrderDate", title: "订单日期", type: "date", width: 120 },
]);
</script>
跨页选择
<template>
<div class="table-item">
<div class="table-item-header">
<vol-title icon="edit" title="跨页选择"></vol-title>
<div class="table-item-buttons">
<el-button type="primary" @click="getSelected" plain>获取所有选中行</el-button>
<el-button type="primary" @click="clearSelection" plain>清除选中</el-button>
</div>
</div>
<!--
row-key: 必须设置,用于标识行的唯一值(通常是主键字段)
reserve-selection: 开启跨页选择功能
-->
<vol-table
ref="tableRef"
row-key="Id"
:reserve-selection="true"
ck
:url="url"
:columns="columns"
:max-height="maxHeight"
:pagination-hide="false"
:load-key="true"
></vol-table>
</div>
</template>
<script lang="jsx" setup>
import VolTable from "@/components/basic/VolTable.vue";
import { ref, reactive, getCurrentInstance } from "vue";
const { proxy } = getCurrentInstance();
const tableRef = ref();
const maxHeight = ref(document.body.clientHeight - 250);
const url = ref("api/Demo_Order/getPageData");
// 获取所有分页选中的行
const getSelected = () => {
const rows = tableRef.value.getSelected();
proxy.$message.success(`已选中 ${rows.length} 行`);
console.log("选中的行:", rows);
};
// 清除所有选中
const clearSelection = () => {
tableRef.value.clearSelection();
proxy.$message.success("已清除选中");
};
// 表格列配置
const columns = reactive([
{ field: "OrderNo", title: "订单编号", type: "string", width: 130 },
{ field: "OrderType", title: "订单类型", type: "int", width: 100 },
{ field: "TotalPrice", title: "总价", type: "decimal", width: 100 },
]);
</script>
拖拽排序
<template>
<div class="table-item">
<div class="table-item-header">
<vol-title icon="edit" title="拖拽排序"></vol-title>
</div>
<!--
sortable: 开启拖拽排序
onSortEnd: 排序结束事件
-->
<vol-table
ref="tableRef"
:table-data="tableData"
:columns="columns"
:max-height="maxHeight"
:pagination-hide="true"
:sortable="true"
@onSortEnd="onSortEnd"
></vol-table>
</div>
</template>
<script lang="jsx" setup>
import VolTable from "@/components/basic/VolTable.vue";
import { ref, reactive, getCurrentInstance } from "vue";
const { proxy } = getCurrentInstance();
const tableRef = ref();
const maxHeight = ref(document.body.clientHeight - 236);
// 拖拽排序结束事件
const onSortEnd = (rows, newIndex, oldIndex) => {
proxy.$message.info(`行从位置 ${oldIndex} 移动到位置 ${newIndex}`);
// rows 是排序后的表格数据,可以在这里保存排序结果
};
// 表格数据
const tableData = reactive([
{ OrderNo: "D001", OrderType: 1, TotalPrice: 100 },
{ OrderNo: "D002", OrderType: 2, TotalPrice: 200 },
{ OrderNo: "D003", OrderType: 3, TotalPrice: 300 },
]);
// 表格列配置
const columns = reactive([
{ field: "OrderNo", title: "订单编号", type: "string", width: 130 },
{ field: "OrderType", title: "订单类型", type: "int", width: 100 },
{ field: "TotalPrice", title: "总价", type: "decimal", width: 100 },
]);
</script>
