跳至主要內容

snippet

chanchaw大约 2 分钟react

数组 To 树形

/**
 * 数组转树形结构
 * @param {array} arr 被转换的数组
 * @param {number|string} root 根节点(最外层节点)
 * @returns array
 */
function arrayToTreeV3(arr, rootVal, fieldConfig) {
  return arr.filter(item => item[fieldConfig.pid] === rootVal).map(item => ({ ...item, children: arrayToTreeV3(arr, item[fieldConfig.id], fieldConfig) }))
}

// 测试用数据
const menuItems = [
  {id:1, name:'根节点',pid:0},
  {id:2, name:'一级子节点01',pid:1,},
  {id:3, name:'一级子节点02',pid:1,},
  {id:4, name:'二级子节点01',pid:2,},
]

// 数组中对象的关键字段描述
const fieldConfig = {
  id: 'id',   // 主键字段=唯一字段
  pid: 'pid', // 所属上级的字段
}
const root = arrayToTreeV3(menuItems,0,fieldConfig)
console.log(root)

树形转换为数组

// 测试用数据
const treeData = [
  {
    id:1000,label:'江苏',children:[
      {id:1001,label:'徐州',children:[
        {id:100101,label:'泉山区'},{id:100102,label:'云龙区'},{id:100103,label:'鼓楼区'},{id:100104,label:'九里区'},{id:100105,label:'铜山区'}
      ]},
      {id:1002,label:'南京'},
      {id:1003,label:'苏州',children:[
        {id:100301,label:'常熟'},{id:100302,label:'昆山'},{id:100303,label:'张家港'},{id:100304,label:'吴江'},{id:100305,label:'姑苏区'},{id:100306,label:'平江区'}
      ]},
    ]
  },
  {id:2000,label:'浙江'},
  {
    id:3000,label:'上海',children:[
    {id:3001,label:'静安区'},{id:3002,label:'浦东区'},{id:3003,label:'徐汇区'},{id:3004,label:'青浦区'},
  ]}
]

// 将树形数据转换为数组
// treeData: 树形结构数组(node组成的数组)
// fieldConfig:字段映射表,3个属性id,pid,children依次表示node的主键,上级字段,子节点属性
// pid:本节点的上级节点(父级节点的主键,第一次调用时传入0)
// nodeArr:node最终形成的数组,初次调用时传入空数组
function tree2Arr(treeData,fieldConfig,pid,nodeArr){
  if(!treeData || treeData.length === 0 ) return null
  for(const node of treeData){
    if(!node) continue
    const childrenNodes = node[fieldConfig.children]
    if(childrenNodes && childrenNodes.length > 0){
      const childrenNodesCoped = JSON.parse(JSON.stringify(childrenNodes))
      delete node[fieldConfig.children]
      tree2Arr(childrenNodesCoped,fieldConfig,node[fieldConfig.id],nodeArr)
    }
    node[fieldConfig.pid] = pid
    nodeArr.push(node)
  }
}
// 测试
function test02(){
  const arr = []
  const fieldConfig = {id:'id', pid:'pid',children:'children'}
  tree2Arr(treeData,fieldConfig,0,arr)
  console.log('树形数据转换后的数组:', arr)
}

遍历树形数据返回节点对象

treeData 是树形数据节点构成的数组(没有一个根节点的树形结构数据),遍历树形结构时对比属性 fieldName 的值等于 fieldVal 的节点,返回给调用者

console.log('tree.js')
const treeData = [
  {
    id:1000,label:'江苏',children:[
      {id:1001,label:'徐州',children:[
        {id:100101,label:'泉山区'},{id:100102,label:'云龙区'},{id:100103,label:'鼓楼区'},{id:100104,label:'九里区'},{id:100105,label:'铜山区'}
      ]},
      {id:1002,label:'南京'},
      {id:1003,label:'苏州',children:[
        {id:100301,label:'常熟'},{id:100302,label:'昆山'},{id:100303,label:'张家港'},{id:100304,label:'吴江'},{id:100305,label:'姑苏区'},{id:100306,label:'平江区'}
      ]},
    ]
  },
  {id:2000,label:'浙江'},
  {
    id:3000,label:'上海',children:[
    {id:3001,label:'静安区'},{id:3002,label:'浦东区'},{id:3003,label:'徐汇区'},{id:3004,label:'青浦区'},
  ]}
]

// 默认下级属性:children
function getNode8Attr(treeNodeList, fieldName, fieldVal){
  if(!treeNodeList || treeNodeList.length === 0) return null
  for(const node of treeNodeList){
    const match = node[fieldName] == fieldVal
    if(match) return node
    const children = node.children || []
    let node01 = null
    if(children.length !== 0) node01 = getNode8Attr(children, fieldName, fieldVal)
    if(node01) return node01
  }
  return null
}

function test01(){
  const retNode = getNode8Attr(treeData,'label','浙江')
  console.log('遍历树形得到的节点是:',retNode)
}