JS 树形数据 Tree的通用方法

点击查看代码

/**
 * @description 查找包含自身节点的父代节点
 * @param list 列表数据
 * @param id 节点 id
 * @param pid 节点的父id
 */
export function listToTree(list, id, pid) {
  list.forEach((node) => {
    const pNdoe = list.find((row) => row[id] === node[pid])

    if (pNdoe) {
      pNdoe.children = pNdoe.children || []
      pNdoe.children.push(node)
    }
  })
  return list.filter((node) => !node[pid])
}

// data 是树型数组
// key 是String 对象中的key值
// value 是key值符合的条件
export function getAllChidlren(data, key, value) {
  var result = [];
  var fn = function(data) {
    if (Array.isArray(data)) { // 判断是否是数组并且没有的情况下,
      data.forEach(item => {
        if (item[key] === value) { // 数据循环每个子项
          result.push(item); // 返回的结果等于每一项
        } else if (item.children) {
          fn(item.children); // 递归调用下边的子项
        }
      })
    }
  }
  fn(data); // 调用一下
  return result;
}

// 树结构过滤即保留某些符合条件的节点,剪裁掉其它节点。一个节点是否保留在过滤后的树结构中,取决于它以及后代节点中是否有符合条件的节点。可以传入一个函数描述符合条件的节点:
export function treeFilter(tree, func) {
  // 使用map复制一下节点,避免修改到原树
  return tree.map(node => ({ ...node })).filter(node => {
    node.children = node.children && treeFilter(node.children, func)
    return func(node) || (node.children && node.children.length)
  })
}

// 查找节点其实就是一个遍历的过程,遍历到满足条件的节点则返回,遍历完成未找到则返回null。类似数组的find方法,传入一个函数用于判断节点是否符合条件
export function treeFind(tree, func) {
  for (const data of tree) {
    if (func(data)) return data
    if (data.children) {
      const res = treeFind(data.children, func)
      if (res) return res
    }
  }
  return null
}

// 因为不知道符合条件的节点在哪个子树,要用到回溯法的思想。查找路径要使用先序遍历,维护一个队列存储路径上每个节点的id,假设节点就在当前分支,如果当前分支查不到,则回溯
export function treeFindPath(tree, func, path = []) {
  if (!tree) return []
  for (const data of tree) {
    path.push(data.id)
    if (func(data)) return path
    if (data.children) {
      const findChildren = treeFindPath(data.children, func, path)
      if (findChildren.length) return findChildren
    }
    path.pop()
  }
  return []
}

/**
 * @description 遍历 tree 给 tree 添加数据
 * @param tree tree 数据
 * @param func 返回追加的属性{key1:value1,key2:value2}
 */
export function formatTree(treeData, func) {
  const dfs = (treeData) => {
    for (const node of treeData) {
      if (func(node)) {
        Object.assign(node, func(node))
      }
      if (node.children && node.children.length) {
        dfs(node.children)
      }
    }
    return treeData
  }
  return dfs(treeData)
}

//js树结构根据条件查找节点返回节点路径
export function findPathbyName(tree, name, path = []) {
  if (typeof path === 'undefined') {
    path = []
  }
  for (let i = 0; i < tree.length; i++) {
    let tempPath = [...path]
    tempPath.push(tree[i].meta.title)
    if (tree[i].name === name) {
      return tempPath
    }
    if (tree[i].children) {
      const reuslt = findPathbyName(tree[i].children, name, tempPath)
      if (reuslt) {
        return reuslt
      }
    }
  }
}
posted @ 2023-05-25 14:09  乌卡拉卡  阅读(305)  评论(0编辑  收藏  举报