一、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 = num
setExpandKeys(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.children
newData.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: number
date: string
name: string
address: string
hasChildren?: boolean
level: 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>
三、效果
我只定义了三层数据,就只演示展开了三层,还可以多层,自己设置即可