vxe-table 同时实现合并单元格与任意列展开行
前一段时间有一个需求,要求既要合并单元格,又要实现树状图的效果,但是展开节点tree-node 可以放在非第一列的任意位置,Vxe-table可以实现如下是效果图:
大家可以一起交流学习!
~效果图
~Template
<template><div><p><vxe-button @click="toggleExpandEvent">切换第一个</vxe-button><vxe-button @click="setExpandEvent">展开第三个</vxe-button><vxe-button @click="expandAllEvent">展开所有</vxe-button><vxe-button @click="claseExpandEvent">关闭所有</vxe-button></p><vxe-tablebordershow-overflowref="tableRef":column-config="{ resizable: true }":tree-config="{ transform: true }":edit-config="{ trigger: 'click', mode: 'cell' }":data="tableData":span-method="objectSpanMethod"header-row-class-name="headerRowClass"><vxe-columnfield="userName"title="用户名":edit-render="{ autofocus: ' .vxe-input--inner' }"><template #edit="{ row }"><vxe-input v-model="row.userName" /></template></vxe-column><vxe-columnfield="targetNum"title="数量":edit-render="{ autofocus: ' .vxe-input--inner' }"><template #edit="{ row }"><vxe-input v-model="row.targetNum" mode="text" type="number" /></template></vxe-column><vxe-columnfield="dilieverSite"title="项目交付地":edit-render="{ autofocus: ' .vxe-input--inner' }"><template #edit="{ row }"><vxe-input v-model="row.dilieverSite" mode="text" /></template></vxe-column><vxe-columnfield="name"title="名字":edit-render="{ autofocus: ' .vxe-input--inner' }"tree-node><template #edit="{ row }"><vxe-input v-model="row.name" transfer /></template></vxe-column><vxe-columnfield="type"title="类型":edit-render="{ autofocus: ' .vxe-input--inner' }"><template #edit="{ row }"><vxe-input v-model="row.type" transfer /></template></vxe-column><vxe-columnfield="size"title="尺寸":edit-render="{ autofocus: ' .vxe-input--inner' }"><template #edit="{ row }"><vxe-input v-model="row.size" transfer /></template></vxe-column><vxe-column title="删除小条目" width="80"><template #default="{ row }"><el-icon@click="handleERPDelete(row)"class="el-icon-delete"color="#F56C6C"><Delete/></el-icon></template></vxe-column><vxe-column field="oper" title="操作" width="100"><template #default="{ row }"><el-button @click="handleAdd(row)" link size="small" type="primary">新增</el-button><el-button @click="handleDelete(row)" link size="small" type="danger">删除</el-button></template></vxe-column></vxe-table></div>
</template>
~script
<script lang="ts" setup>
import { ref, onMounted } from "vue";
import { ElMessageBox } from "element-plus";
import type {VxeTablePropTypes,VxeTableEvents,VxeTableInstance
} from "vxe-table";
interface RowVO {id: number;userName: string;dilieverSite: string;targetNum: number;parentId: number | null;name: string;type: string;size: number;date: string;oper?: string;
}const tableData = ref<RowVO[]>([{id: 10000,parentId: null,userName: "宁夏宝丰",dilieverSite: "中国-灵武",targetNum: 3,name: "test abc1",type: "mp3",size: 1024,date: "2020-08-01"},{id: 10050,parentId: null,userName: "宁夏宝丰",dilieverSite: "中国-灵武",targetNum: 3,name: "Test2",type: "mp4",size: 0,date: "2021-04-01"},{id: 24300,parentId: 10050,userName: "宁夏宝丰",dilieverSite: "中国-灵武",targetNum: 3,name: "Test3",type: "avi",size: 1024,date: "2020-03-01"},{id: 20045,parentId: 24300,userName: "宁夏宝丰",dilieverSite: "中国-灵武",targetNum: 3,name: "test abc4",type: "html",size: 600,date: "2021-04-01"},{id: 10053,parentId: 24300,userName: "宁夏宝丰",dilieverSite: "中国-灵武",targetNum: 3,name: "test abc96",type: "avi",size: 0,date: "2021-04-01"},{id: 24330,parentId: 10053,userName: "宁夏宝丰",dilieverSite: "中国-灵武",targetNum: 3,name: "test abc5",type: "txt",size: 25,date: "2021-10-01"},{id: 21011,parentId: 10053,userName: "宁夏宝丰",dilieverSite: "中国-灵武",targetNum: 3,name: "Test6",type: "pdf",size: 512,date: "2020-01-01"},{id: 22200,parentId: 10053,userName: "宁夏宝丰",dilieverSite: "中国-灵武",targetNum: 3,name: "Test7",type: "js",size: 1024,date: "2021-06-01"},{id: 23666,parentId: null,userName: "宁夏宝丰",dilieverSite: "中国-灵武",targetNum: 3,name: "Test8",type: "xlsx",size: 2048,date: "2020-11-01"},{id: 23677,parentId: 23666,userName: "宁夏宝丰",dilieverSite: "中国-灵武",targetNum: 3,name: "Test7",type: "js",size: 1024,date: "2021-06-01"},{id: 23671,parentId: 23677,userName: "宁夏宝丰",dilieverSite: "中国-灵武",targetNum: 3,name: "Test7",type: "js",size: 1024,date: "2021-06-01"},{id: 23672,parentId: 23677,userName: "宁夏宝丰",dilieverSite: "中国-灵武",targetNum: 3,name: "Test7",type: "js",size: 1024,date: "2021-06-01"},{id: 23688,parentId: 23666,userName: "宁夏宝丰",dilieverSite: "中国-灵武",targetNum: 3,name: "Test7",type: "js",size: 1024,date: "2021-06-01"},{id: 23681,parentId: 23688,userName: "宁夏宝丰",dilieverSite: "中国-灵武",targetNum: 3,name: "Test7",type: "js",size: 1024,date: "2021-06-01"},{id: 23682,parentId: 23688,userName: "宁夏宝丰",dilieverSite: "中国-灵武",targetNum: 3,name: "Test7",type: "js",size: 1024,date: "2021-06-01"},{id: 24555,parentId: null,userName: "宁夏宝丰",dilieverSite: "中国-灵武",targetNum: 3,name: "test abc9",type: "avi",size: 224,date: "2020-10-01"},{id: 24566,parentId: 24555,userName: "宁夏宝丰",dilieverSite: "中国-灵武",targetNum: 3,name: "Test7",type: "js",size: 1024,date: "2021-06-01"},{id: 24577,parentId: 24555,userName: "宁夏宝丰",dilieverSite: "中国-灵武",targetNum: 3,name: "Test7",type: "js",size: 1024,date: "2021-06-01"}
]);const setTabelRowSpan = (tableData: any, fieldArr: any, effectMerge = {}) => {let lastItem = {};fieldArr.forEach((field: any, index: any) => {let judgeArr = fieldArr.slice(0, index + 1);if (effectMerge[field]) {judgeArr = [...effectMerge[field], field];}tableData.forEach((item: any) => {item.mergeCell = fieldArr;const rowSpan = `rowspan_${field}`;if (judgeArr.every((e: any) => lastItem[e] === item[e] && item[e] !== "")) {item[rowSpan] = 0;lastItem[rowSpan] += 1;} else {item[rowSpan] = 1;lastItem = item;}});});
};
const executeMerge = (data: any) => {// let effectRows = [0];// let fieldArr = ["userName"]; //全部字段let RowfieldArr = ["userName", "dilieverSite", "targetNum"];//setTableColumnSpan(data, fieldArr, effectRows); // (表格数据,表格字段,合并列setTabelRowSpan(data, RowfieldArr); // (表格数据,表格字段,合并的条件)//如果要用到合并条件:参考如下// const effectMerge = {// dilieverSite: ['userName'],//参照userName字段合并// targetNum: ['userName']//// }
};onMounted(() => {executeMerge(tableData.value);
});const tableRef = ref<VxeTableInstance<RowVO>>();const colspanMethod: VxeTablePropTypes.SpanMethod<RowVO> = ({row,_rowIndex,column,columnIndex
}) => {if (columnIndex === 1) {console.log("row", row);}
};const toggleExpandEvent = () => {const $table = tableRef.value;if ($table) {$table.toggleTreeExpand(tableData.value[1]);}
};const setExpandEvent = () => {const $table = tableRef.value;if ($table) {$table.setTreeExpand(tableData.value[8], true);}
};const expandAllEvent = () => {const $table = tableRef.value;if ($table) {$table.setAllTreeExpand(true);}
};const claseExpandEvent = () => {const $table = tableRef.value;if ($table) {$table.clearTreeExpand();}
};const objectSpanMethod: VxeTablePropTypes.SpanMethod<any> = ({row,column,rowIndex,columnIndex
}) => {// if (effectRows.includes(rowIndex)) {// const colspan = row[`colspan_${column.property}`];// if (colspan) {// return { rowspan: 1, colspan: colspan };// } else {// return { rowspan: 0, colspan: 0 };// }// }if (row.mergeCell.includes(column.property)) {const rowspan = row[`rowspan_${column.property}`];if (rowspan) {return { rowspan: rowspan, colspan: 1 };} else {return { rowspan: 0, colspan: 0 };}} else if (column.property === "oper") {const rowspan = row[`rowspan_userName`];if (rowspan) {return { rowspan: rowspan, colspan: 1 };} else {return { rowspan: 0, colspan: 0 };}}
};const handleAdd = row => {console.log(row);
};const handleDelete = row => {console.log(row);
};const handleERPDelete = row => {ElMessageBox.confirm("确定要删除吗?", "提示", {confirmButtonText: "确定",cancelButtonText: "取消",type: "warning"}).then(() => {console.log(row);});
};
</script>