数组转树形的用途 为什么面试的时候会问关于它呢,其实这种树形结构的数据在项目中还是很常见的。树形结构的数据的主要用途就是供菜单渲染使用。不过这种数据的返回一般是由后端人员完成的,也不排除由前端人员转换的情况。
前端转换的场景:当我们拿到用户角色对应的菜单权限数组时,像:[home,goods,goodsmanage,chart,line] ,还拿到了整个菜单的数组列表,我们需要根据用户的权限来动态渲染出对应的菜单,此时我们应该如何处理呢?
1.根据整个菜单的数组列表和权限数组,生成该用户对应的菜单列表
2.把菜单列表转化为树形结构对象
3.根据树形结构对象渲染对应的菜单
数组转树形 现有后台返回的用户信息和完整菜单数组数据如下: 完整菜单数组
const list=[
{id:"0",pid:"",title:"菜单",key:'menu'},
{id:"1",pid:"0",title:"首页",key:'home'},
{id:"2",pid:"0",title:"商品",key:'goods'},
{id:"2-1",pid:"2",title:'商品管理',key:'goodsmanage'},
{id:"2-2",pid:'2',title:'商品分类',key:'goodscategory'},
{id:"3",pid:"0",title:"图表管理",key:'chart'},
{id:"3-1",pid:'3',title:"饼图",key:'pie'},
{id:"3-2",pid:'3',title:"条形图",key:'bar'},
{id:"3-3",pid:'3',title:"折线图",key:'line'}
]
用户信息
const user={
name:'xxx',
role:'xx'
auth:['home','goods','goodsmanage','goodscategory','chart','pie']
}
1.先找到该角色对应的菜单列表
const myList=[] // 定义该用户对应的菜单列表
for(let i of list)
{
// 如果找到用户对应的菜单项,把该菜单项加进去
if(user.auth.indexOf(i.key)!==-1) myList.push(i)
}
2.开始转树形 方法一:非递归思路 把所有孩子收纳到各自麾下,然后只需找到根节点即可。因为根节点会收纳自己的孩子,根节点的孩子也会收纳自己的孩子,以此类推。因此我们只需要找到根节点就相当于找到整颗树形了。
function createTree(arr=[]){
let res
for(let i of arr){
for(let j of arr){
if(!i.pid) res=i // 找到根节点
if(i.id==j.pid) // 让每个节点都去去寻找自己的子节点,然后将子节点收入其中
{
if(!i.children)i.children=[]
i.children.push(j)
}
}
}
return res
}
const myTree=createTree(myList)
console.log(myTree)
方法二:递归思路 先找到根节点,然后把根节点的直接孩子收入自己麾下,收入的孩子是递归后的孩子。(递归后的孩子会找到自己的孩子)
function createTree(arr=[],id){
let res={}
for(let i of arr){
if(id==i.id) { // 先找到跟节点
res.title=i.title
}
if(id==i.pid){ // 把根节点的直接子节点递归收入其中
if(!res.children) res.children=[]
res.children.push(createTree(arr,i.id))
}
}
return res
}
const myTree=createTree(list,"0") // 0是根节点的id
console.log(myTree)
3.渲染菜单,以antd的Menu组件为例。
import {PureComponent} from "react"
import {Menu} from 'antd'
class index extends PureComponent{
linkto=(i)=>{
this.props.history.push(`${this.props.match.path}/${i.keyPath.reverse().join('/')}`)
}
render() {
return (
<div className='leftnav'>
<Menu
defaultSelectedKeys={keys}
defaultOpenKeys={keys}
mode="inline"
theme="dark"
items={this.state.myTree.children} {/*这里的myTree就是上面的树形数据*/
onClick={this.linkto}
/>
</div>
)
}
}
export default index
树形转数组
其实树形结构转数组涉及到了数据结构关于树的算法,例:先序遍历、中序遍历、后序遍历、层序遍历,区别就在于节点输出的顺序不一致。如果想了解关于树的这些算法,可以看看我发布的一篇文章——>js实现树的前、中、后、层序遍历。
function treeToList(obj={}){
const res=[]
function a(obj={}){
res.push({id:obj.id,pid:obj.pid})
if(obj.children){
for(let v of obj.children){
a(v)
}
}
}
a(obj)
return res
}
const list=treeToList(myTree)
console.log(list)