效果图
需求是做一个这种的多层级表格,树形数据表格。
大家可能遇到的问题
一种是不知道如何做这种多层级的表格
一种是后台给自己返回的数据不是树形的,也就是没有子父级。全是一条条的扁平化数组。类似这样
而我们需要的结构是这样
那么问题就来了,我们如何把这一段数据给处理转换成树形结构呢。
我在网上看了好多的帖子学习,发现很多都是写的很复杂或者只写了一部分,那我就来弄一个全覆盖的额好了,从如何做表,到万一给你的是扁平数组如何转换成树行的。一次搞定
扁平数组转换树形结构方法
这个也是网上看到一个算法大佬的写法,经过测试,确实有效,而且特别简便。
setTreeData(source){
let cloneData = JSON.parse(JSON.stringify(source)) // 对源数据深度克隆
return cloneData.filter(father=>{ // 循环所有项,并添加children属性
let branchArr = cloneData.filter(child=> father.menuId == child.parentId); // 返回每一项的子级数组
branchArr.length>0 ? father.children=branchArr : '' //给父级添加一个children属性,并赋值
return father.parentId==0; //返回第一层
});
解释一下用法:
1,你需要发请求获取后台给你的数组,然后在你的.then()内调用这个setTreeData方法,并把你们的数组传参过去,比如这样this.setTreeData(data),这个data就是你请求拿到的数据。
2,你需要看一下这里面的father.menuId这句话,他对应的是id,因为我的项目后台返回的id他取名是menuId所以我改成了menuid,你们要看下自己的数据里是id还是什么其他名字,修改一下就能用了,后面的parentId我看了很多人的数据,基本都是一样的名字,没有人动这个的,如果不一样,那也需要改一下。
解释一下逻辑:
很简单的逻辑,首先把拿到的数据克隆一份存到cloneData变量内,然后循环这个变量,两个filter循环的逻辑是把第一项的id和所有项的parentId做比较,parentId代表上级菜单,一般这个上级菜单写的就是上级菜单的id一样的,所以我们比较一下,如果是一致的,那就代表这个是第一项的子级,那就返回这一项到branchArr内。一直循环比较完毕后,接下继续循环第二项,还是一样第二项的id和所有项的parentId比较找一样的给到branchArr内,然后第三项,第四项以此类推把所有id都比较一遍后就找到了所有id对应的子级,这时候判断branchArr长度大于0吗,如果大于代表有子级,那就创建一个childern字段,值就是branchArr的数据。最后把parentId==0的返回,等于0代表没有上级菜单,那他就是最顶级的菜单,所以他返回了就是第一层的菜单。
好啦,到这里大家应该懂了这个树形转换的逻辑了吧。那我们开始说如何把表格做出来。
这就需要用到我们的elementul组件了,非常方便。
树形数据表格
<template>
<div>
<el-table
:data="tableData"
style="width: 100%;margin-bottom: 20px;"
row-key="id"
border
default-expand-all
:indent="20"
:tree-props="{children: 'children', hasChildren: 'hasChildren'}">
<el-table-column
prop="date"
label="日期"
sortable
width="180">
</el-table-column>
<el-table-column
prop="name"
label="姓名"
sortable
width="180">
</el-table-column>
<el-table-column
prop="address"
label="地址">
</el-table-column>
</el-table>
</div>
</template>
<script>
export default {
data() {
return {
tableData: [ {
id: 3,
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄',
children: [{
id: 31,
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄'
}, {
id: 32,
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄',
children: [{
id: 34,
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄'
}, {
id: 35,
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄'
}]
}]
}, {
id: 4,
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1516 弄'
}],
}
},
methods: {
load(tree, treeNode, resolve) {
setTimeout(() => {
resolve([
{
id: 31,
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄'
}, {
id: 32,
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄'
}
])
}, 1000)
}
},
}
</script>
解释一下写法:
这其时就是elementul官网上复制的一段代码,table表格组件有一个树形数据与懒加载的表格可以参考。
重点说一下注意点。
写在el-table标签上的属性意思解释:
两个必须要写的,row-key="id"这个id对应你的数据的id或者像我一样的menuId。反正别重复,是一个标记区分的作用。tree-props的意思是,再你的数据内如果哪一条有children字段就展开,里面放子级,刚好我们刚才数据已经转换了,现在里面有children字段了可以用来判断,这个地方注意的是children: 'children’这个前面不能改,后面的名字可以改,根据你数据里面的子级字段改,比如我们正常人的子级都是用children表示,如果你们公司的后端比较叛逆偏偏要用ABC来表示,那就是children: 'ABC’懂吧。
至于后面的hasChildren: 'hasChildren’基本用不到。
row-key="id"
:tree-props="{children: 'children', hasChildren: 'hasChildren'}"
这个indent意思就是你表格展开后的偏移量,每一级首行缩进多少。也是加在el-table上的属性
:indent="20"
还可以在el-table上加一个lazy属性,代表了子级懒加载。