tree-helper.js 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. import _ from "lodash";
  2. /**
  3. * @description 在树结构中查找路径
  4. * @param {Object[]} tree - 树的根节点数组
  5. * @param {Function} predicate - 要查找的目标条件
  6. * @param {string} children - 属性名,默认`children`
  7. * @param {string[]} path - 当前路径(递归用)
  8. * @returns {Object[] | null} - 返回路径数组,如果没找到返回 null
  9. */
  10. export function findTreePath(tree, predicate, children = 'children', path = []) {
  11. if (!Array.isArray(tree)) throw new TypeError('tree must be an array')
  12. if (typeof predicate !== 'function') throw new TypeError('predicate must be a function')
  13. for (const node of tree) {
  14. if (!node) continue
  15. // 添加当前节点到路径
  16. const currentPath = [...path, node];
  17. // 检查当前节点的值是否匹配
  18. if (predicate(node)) return currentPath;
  19. // 如果有子节点,递归查找
  20. if (node[children]?.length) {
  21. const result = findTreePath(node[children], predicate, children, currentPath);
  22. if (result) {
  23. return result; // 找到路径则返回
  24. }
  25. }
  26. }
  27. // 如果未找到目标值,返回 null
  28. return null;
  29. }
  30. export function findTreeNode(tree, predicate, children = 'children') {
  31. const path = findTreePath(tree, predicate, children)
  32. return _.last(path)
  33. }
  34. export function convertStandardTree(
  35. root,
  36. labelKey = 'label',
  37. valueKey = 'value',
  38. childrenKey = 'children',
  39. toLabel = 'label',
  40. toValue = 'value',
  41. toChildren = 'children') {
  42. const convertor = (node) => ({
  43. [toLabel]: node[labelKey],
  44. [toValue]: node[valueKey],
  45. [toChildren]: node[childrenKey]?.map(convertor)
  46. })
  47. const arrRoot = Array.isArray(root) ? root : [root]
  48. return arrRoot.map(convertor)
  49. }
  50. export function fillTreeChildCount(tree) {
  51. const fillChildCount = (node) => {
  52. node.childCount = node.children?.length || 0
  53. node.children?.forEach(child => fillChildCount(child))
  54. }
  55. [].concat(tree).forEach(node => fillChildCount(node))
  56. }
  57. export function fillTreeParentBridge(tree) {
  58. const fillParent = (node, parent = null, root = null) => {
  59. node.parent = parent
  60. node.root = root
  61. if (!node.children?.length) return
  62. node.children.forEach(child => fillParent(child, node, root || node))
  63. }
  64. [].concat(tree).forEach(node => fillParent(node))
  65. }