js无限层级, 递归遍历

来源数据结构

const productInfoList = [{
	productId: 2,
	productName: '2',
	parentId: 1
},{
	productId: 1,
	productName: '1',
	parentId: ''
},{
	productId: 3,
	productName: '3',
	parentId: 2
},{
	productId: 4,
	productName: '4',
	parentId: ''
}]
// ...无限层级,父子乱序

目标期望数据结构

const target = [{
	label: '1',
	id: 1,
	children: [{
		label: '2',
		id: 2,
		children: [{
			label: '3',
			id: 3,
			children: []
		}]
	}]
},{
	label: '4',
	id: 4,
	children: []
}]

业务逻辑

const infinite = (id, target = this.product.menu, source = productInfoList) => {
  for (const i in source) {
    if (source[i].parentId === id) {
      target.push({
        label: source[i].productName,
        id: source[i].productId,
        children: []
      })
      infinite(source[i].productId, target[target.length - 1].children)
    }
  }
}
infinite('') // 已知根节点id为 ''

// 无限层级,乱序数组,未知根节点

const source = [{
  productId: 2,
  name: '2',
  parentId: 1
}, {
  productId: 1,
  name: '1',
  parentId: 99
}, {
  productId: 4,
  name: '4',
  parentId: ''
}, {
  productId: 6,
  name: '6',
  parentId: 1
}, {
  productId: 3,
  name: '3',
  parentId: 1
}, {
  productId: 7,
  name: '7',
  parentId: 2
}, {
  productId: 8,
  name: '8',
  parentId: 66
}, {
  productId: 5,
  name: '5',
  parentId: 4
}]

const infiniteLevel = {
  init(source, formate) {
    this.target = [] // 用于临时存储结果
    this.source = source // 用户来源集合
    this.formateSub = formate || function() {} // 用户自定义格式化内容
    for (const index in this.source) {
      this.infinite(this.source[index], index) // 开始无限递归遍历,index参数用于判断是init执行的infinite还是自己递归执行的
    }
    return this.setResult() // 返回最终结果
  },
  formate(item) { // 用于格式化每一项,根据项目实际需求设置
    const sub = this.formateSub(item)
    return Object.assign({
      label: item.name,
      id: item.id,
      pid: item.pid,
      level: item.level || 0,
      children: item.children || []
    }, sub)
  },
  infinite(item, index) {
    const result = this.formate(item)
    if (index === undefined) result.level ++ // index用于判断level,如果有index就证明是第一次开始计算层级,如果是undefined就是递归来的叠加层级。
    let isParent = null
    const children = []
    this.source.forEach(s => {
      const formateS = this.formate(s)
      if (formateS.id === result.pid) isParent = s // 判断每一项的父级是否存在,由于来源中的id可能不存在,要先进行格式化。
      if (formateS.pid === result.pid) children.push(formateS) // 找到所有的同级
    })
    if (isParent) { // 如果父级存在继续递归向上寻找祖父级直至根级
      isParent.children = children // 将刚刚获取到的所有子集放入该父级节点下
      isParent.level = result.level // 新增level属性,用于判断该父级存在几级子节点,用于最后找到包含层级最多的父级,也就是根级。
      this.infinite(isParent)
    } else {
      this.target.push(result)
    }
  },
  setResult() {
    const result = []
    this.target.sort((a, b) => {
      return b.level - a.level
    }).forEach(e => {
      if (!result.some(r => r.id === e.id) && !isNaN(e.level)){
        result.push(e)
      }
    })
    return result
  }
}

console.log(infiniteLevel.init(source, (item) => {
  return {
    id: item.productId,
    pid: item.parentId
  }
}))

你可能感兴趣的:(JavaScript,javascript)