一、TableTreeLevel组件
<template><div class='main'><div class="btns"><el-button type="primary" @click="expandLevel(1)">展开一级</el-button><el-button type="primary" @click="expandLevel(2)">展开二级</el-button><el-button type="primary" @click="expandLevel(3)">展开三级</el-button><el-button type="primary" @click="expandLevel(4)">展开四级</el-button><el-button type="warning" @click="putAwayLevel(0)">全部收起</el-button></div><div><el-table ref="multipleTableRef" :height="height" :default-expand-all="isExpend" :data="treeTableData"style="width: 100%; margin-bottom: 20px" row-key="id" border><el-table-column :width="item.width" :fixed="item.fixed" show-overflow-tooltip align="center"v-for="(item, i) in treeTableProps" :key="i" :label="item.label"><template #default="scope"><!-- 自定义插槽展示 --><slot v-if="item.slot" :name="item.prop" :scope="scope"></slot><!-- 非自定义处理(判空) --><span v-else-if="scope.row[item.prop] === '' || scope.row[item.prop] === null">--</span><!-- 非自定义处理(正常展示) --><span v-else>{{ scope.row[item.prop] }}</span></template></el-table-column></el-table></div></div>
</template><script lang="ts" setup>
import { ref, reactive, getCurrentInstance, onMounted, watch } from 'vue'
interface Props {// 属性名prop: string,// 属性标签label: string,// 是否固定(非必填)fixed?: boolean,// 行宽(非必填)width?: number,// 是否显示插槽(非必填)slot?: boolean,
}
const props = defineProps({/** 表格数据 */treeTableData: {type: Array,default: null,required: true},/** 表格属性 */treeTableProps: {type: Array<Props>,default: null,required: true},/** 是否默认全部展开 */isExpend: {type: Boolean,default: false,required: false},/** 表格高度 */height: {type: String,default: '60vh',required: false}
})
const multipleTableRef = ref() //获取table的ref
const expandNum = ref(0) //展开层级的数字/** 监听展开的层级数,如果当前选择的层级小于上一次选择的层级,就收起 */
watch(expandNum, (newValue, oldValue) => {if (newValue < oldValue) {putAwayLevel(newValue + 1)}
}, { deep: true })
/** 收起 */
const putAwayLevel = (num: number) => {let arr = ref(treeToArray(props.treeTableData))//将树形数据转为一维数组,方便一层遍历// 遍历收起当前层级arr.value.map((row: any) => {if (num == row.level) {multipleTableRef.value.toggleRowExpansion(row, false);}})// 下面递归调用目的是:假如你展开了4级,又点击展开2级,这时需要收起的是3级和4级,// 不然它只收起的2级,点开2级的时候,3级其实也是展开的.// 因此细节一点就是:展开2级,需要收起3、4级;展开1级,需要收起2、3、4级;展开3级,需要收起4级;if (++num < 4) {putAwayLevel(num)}
}
/** 展开 */
const expandLevel = (num: number) => {expandNum.value = numsetExpandKeys(props.treeTableData, num)
}/** 递归设置展开层级 */
const setExpandKeys = (dataList: any, level: number) => {// level为要展开的层级,先减一后使用,不然会多展开一级--level;// 当num大于0时,就对数组里面每一层依次进行展开if (level >= 0) {for (var i = 0; i < dataList.length; i++) {// toggleRowExpansion 用于可扩展的表格或树表格, 第二个参数为true则为展开该行,false为折叠。multipleTableRef.value.toggleRowExpansion(dataList[i], true);if (dataList[i].children) {setExpandKeys(dataList[i].children, level);}}}
}
/** 将树形数据转为一维数组的函数*/
const treeToArray = (arr: any) => {let data = JSON.parse(JSON.stringify(arr))let newData = ref([] as any)const callback = (item: any) => {(item.children || (item.children = [])).map((v: any) => {callback(v)})delete item.childrennewData.value.push(item)}data.map((v: any) => callback(v))return newData
}
onMounted(() => {
})</script>
<style scoped lang='less'>
.btns {margin-bottom: 20px;
}@media screen and (min-width: 200px) and (max-width: 1600px) {}@media screen and (min-width: 1601px) {}
</style>
二、使用
<!----------------------------BaseTableTreeLevel的使用-------------------------------><BaseTableTreeLevel :treeTableData="tableData" height="50vh" :treeTableProps="treeTableProps"></BaseTableTreeLevel>
<script lang='ts' setup>
import TableTree from '@/components/BaseTableTree/index.vue'
import { ref, reactive, getCurrentInstance, onMounted } from 'vue'
// 定义表格数据接口
interface dataList {id: numberdate: stringname: stringaddress: stringhasChildren?: booleanlevel: number,children?: dataList[]
}
// 定义表格头部属性名
const treeTableProps = [{ prop: 'date', label: '日期', width: 300, fixed: true, },{ prop: 'name', label: '名称', },{ prop: 'address', label: '地址', slot: true, },
]
// 定义表格假数据
const tableData: dataList[] = [{id: 1,date: '2016-05-04',name: '',address: 'No. 189, Grove St, Los Angeles',level: 1,children: [{id: 11,date: '2016-05-01',name: '小明',address: 'No. 189, Grove St, Los Angeles',level: 2,children: [{id: 111,date: '2016-05-01',name: '小明',address: 'No. 189, Grove St, Los Angeles',level: 3,},{id: 112,date: '2016-05-01',name: '小明',address: 'No. 189, Grove St, Los Angeles',level: 3,}]},{id: 12,date: '2016-05-01',name: '小明',address: 'No. 189, Grove St, Los Angeles',level: 2,},],},{id: 2,date: '2016-05-04',name: '小明',address: 'No. 189, Grove St, Los Angeles',level: 1,children: [{id: 21,date: '2016-05-01',name: '小明',address: 'No. 189, Grove St, Los Angeles',level: 2,children: [{id: 211,date: '2016-05-01',name: '小明',address: 'No. 189, Grove St, Los Angeles',level: 3,},{id: 212,date: '2016-05-01',name: '小明',address: 'No. 189, Grove St, Los Angeles',level: 3,}]},{id: 32,date: '2016-05-01',name: '小明',address: 'No. 189, Grove St, Los Angeles',level: 2,},],},{id: 3,date: '2016-05-01',name: '小明',level: 1,address: 'No. 189, Grove St, Los Angeles',children: [{id: 31,date: '2016-05-01',name: '小明',address: 'No. 189, Grove St, Los Angeles',level: 2,children: [{id: 311,date: '2016-05-01',name: '小明',address: 'No. 189, Grove St, Los Angeles',level: 3,},{id: 312,date: '2016-05-01',name: '小明',address: 'No. 189, Grove St, Los Angeles',level: 3,children: [{id: 3121,date: '2016-05-01',name: '小明',address: 'No. 189, Grove St, Los Angeles',level: 4,}, {id: 3122,date: '2016-05-01',name: '小明',address: 'No. 189, Grove St, Los Angeles',level: 4,},]}]},{id: 32,date: '2016-05-01',name: '小明',address: 'No. 189, Grove St, Los Angeles',level: 2,},],},{id: 4,date: '2016-05-03',name: '小明',address: 'No. 189, Grove St, Los Angeles',level: 1,},
]onMounted(() => {
})</script>
三、效果
我只定义了三层数据,就只演示展开了三层,还可以多层,自己设置即可