Skip to content

树形类 - ikTree

树形数据处理的一些方法

导入方式

import { ikTree } from 'iking-utils'

interface TreeHelperConfig {
  id: string;
  children: string;
  pid: string;
  sort: string; // 排序字段名
  needSort: boolean; // 是否需要排序
}

findNode

在树结构中找到满足给定条件的节点。

找到的节点,如果没有节点满足条件则返回null

script
findNode<T = any>(
  tree: any,
  func: Fn,
  config: Partial<TreeHelperConfig> = {},
): T | null

参数说明

参数值类型参数值说明
treeany要搜索的树结构
funcFn节点要满足的条件函数
configPartial<TreeHelperConfig>树遍历的可选配置

示例

vue
<script setup>
import { ikTree } from  'iking-utils'
//定义一个树形结构
const tree = [
  {
    id: 1,
    name: 'Node 1',
    children: [
      {
        id: 2,
        name: 'Node 2',
        children: [
          {
            id: 3,
            name: 'Node 3',
            children: []
          }
        ]
      },
      {
        id: 4,
        name: 'Node 4',
        children: []
      }
    ]
  },
  {
    id: 5,
    name: 'Node 5',
    children: []
  }
];

//定义一个函数来搜索指定的节点
function findNodeById(node) {
  return node.id === 3;
}

//调用findNode函数查找id为3的节点
const result = ikTree.findNode(tree, findNodeById);

console.log(result); // Output: { id: 3, name: 'Node 3', children: [] }
</script>

findNodeAll

这个函数查找树中与给定函数匹配的所有节点。 它接受一个树对象、一个匹配节点的函数和一个可选的配置对象。 配置对象可以为子节点指定属性名。 该函数返回树中找到的所有匹配节点的数组。

script
findNodeAll<T = any>(
  tree: any,
  func: Fn,
  config: Partial<TreeHelperConfig> = {},
): T | null

参数说明

参数值类型参数值说明
treeany要搜索的树结构
funcFn节点要满足的条件函数
configPartial<TreeHelperConfig>树遍历的可选配置

示例

vue
<script setup>
import { ikTree } from  'iking-utils'
//定义一个树形结构
const tree = [
  {
    id: 1,
    name: 'Node 1',
    children: [
      {
        id: 2,
        name: 'Node 2',
        children: [
          {
            id: 3,
            name: 'Node 3',
            children: []
          }
        ]
      },
      {
        id: 4,
        name: 'Node 4',
        children: []
      }
    ]
  },
  {
    id: 5,
    name: 'Node 5',
    children: []
  }
];

//定义一个函数来搜索具有特定名称的节点
function findNodesByName(node) {
  return node.name.includes('Node');
}

//调用findNodeAll函数查找名称包含'Node'的所有节点
const results = ikTree.findNodeAll(tree, findNodesByName);

console.log(results);
// Output: [
//   { id: 1, name: 'Node 1', children: [...] },
//   { id: 2, name: 'Node 2', children: [...] },
//   { id: 3, name: 'Node 3', children: [] },
//   { id: 4, name: 'Node 4', children: [] },
//   { id: 5, name: 'Node 5', children: [] }
// ]
</script>

findPath

函数用于在树数据结构中查找与给定条件匹配的路径。

script
findPath<T = any>(
  tree: any,
  func: Fn,
  config: Partial<TreeHelperConfig> = {},
): T | T[] | null

参数说明

参数值类型参数值说明
treeany表示需要查找路径的树状数据结构。它可以是任何类型的树。
funcFn这个参数是一个函数,它从树中获取一个节点作为输入,并返回一个布尔值,指示该节点是否符合所需的条件。
configPartial<TreeHelperConfig>该参数是一个可选对象,允许自定义函数的行为。它包括诸如children之类的属性,它指定每个节点中子数组的属性名称。

示例

vue
<script setup>
import { ikTree } from  'iking-utils'
const tree = [
  {
    id: 1,
    name: 'Node 1',
    children: [
      {
        id: 2,
        name: 'Node 2',
        children: [
          {
            id: 3,
            name: 'Node 3',
          },
          {
            id: 4,
            name: 'Node 4',
          },
        ],
      },
      {
        id: 5,
        name: 'Node 5',
      },
    ],
  },
  {
    id: 6,
    name: 'Node 6',
  },
];

// Define your condition function
function findNodeById(node) {
  return node.id === 4;
}

// 调用findPath函数
const path = ikTree.findPath(tree, findNodeById);

console.log(path); // Output: [{ id: 1, name: 'Node 1', children: [{ id: 2, name: 'Node 2', children: [...] },{ id: 5, name: 'Node 5', children: [...] }] }, { id: 2, name: 'Node 2', children: [...] }, { id: 4, name: 'Node 4' }]
</script>

findPathAll

这个函数“findPathAll”接受一个树和一个函数,并返回树中满足给定函数的所有路径的数组。该函数还接受一个配置对象,该对象可以指定用于树中的子节点的键。

script
findPathAll(tree: any, func: Fn, config: Partial<TreeHelperConfig> = {})

参数说明

参数值类型参数值说明
treeany表示需要查找路径的树状数据结构。它可以是任何类型的树。
funcFn这个参数是一个函数,它从树中获取一个节点作为输入,并返回一个布尔值,指示该节点是否符合所需的条件。
configPartial<TreeHelperConfig>该参数是一个可选对象,允许自定义函数的行为。它包括诸如children之类的属性,它指定每个节点中子数组的属性名称。

示例

vue
<script setup>
import { ikTree } from  'iking-utils'
const tree = [
  {
    id: 1,
    name: 'Node 1',
    children: [
      {
        id: 2,
        name: 'Node 2',
        children: [
          {
            id: 3,
            name: 'Node 3',
            children: []
          }
        ]
      },
      {
        id: 4,
        name: 'Node 4',
        children: []
      }
    ]
  },
  {
    id: 5,
    name: 'Node 5',
    children: []
  }
];

// 定义一个函数来搜索具有特定名称的节点
function findNodesByName(node) {
  return node.name.includes('Node');
}

// 调用findPathAll函数查找到名称包含“Node”的所有节点的路径
const results = ikTree.findPathAll(tree, findNodesByName);

console.log(results);
// Output: [
//   [ { id: 1, name: 'Node 1', children: [...] } ],
//   [ { id: 1, name: 'Node 1', children: [...] }, { id: 2, name: 'Node 2', children: [...] } ],
//   [ { id: 1, name: 'Node 1', children: [...] }, { id: 2, name: 'Node 2', children: [...] }, { id: 3, name: 'Node 3', children: [] } ],
//   [ { id: 1, name: 'Node 1', children: [...] }, { id: 4, name: 'Node 4', children: [] } ],
//   [ { id: 5, name: 'Node 5', children: [] } ]
// ]
</script>

filter

根据给定的过滤函数过滤元素树。

script
filter<T = any>(
  tree: T[],
  func: (n: T) => boolean,
  config: Partial<TreeHelperConfig> = {},
): T[]

参数说明

参数值类型参数值说明
treeany要过滤的元素树。
funcFn应用于每个元素的过滤函数。
configPartial<TreeHelperConfig>可选的配置对象,用于自定义树助手的行为。

示例

vue
<script setup>
import { ikTree } from  'iking-utils'
const tree = [
  {
    id: 1,
    name: 'Node 1',
    children: [
      {
        id: 2,
        name: 'Node 2',
        children: [
          {
            id: 3,
            name: 's3',
            children: []
          }
        ]
      },
      {
        id: 4,
        name: 'Node 4',
        children: []
      }
    ]
  },
  {
    id: 5,
    name: 'Node 5',
    children: []
  }
];

// 定义条件函数
function filterNodesWithName(node) {
  return node.name.includes('Node');
}

// 调用findPathAll函数查找到名称包含“Node”的所有节点的路径
const filteredNodes = ikTree.filter(tree, filterNodesWithName);

console.log(filteredNodes);
// Output: [
//   { id: 1, name: 'Node 1', children: [
//     { id: 2, name: 'Node 2', children: [
//       { id: 4, name: 'Node 4' , children: undefined}
//     ]},
//     { id: 5, name: 'Node 5', children: undefined }
//   ]},
//   { id: 6, name: 'Node 6', children: undefined}
// ]
</script>

forEach

用于遍历树状数据结构并在每个节点上执行操作

script
filter<T = any>(
  tree: T[],
  func: (n: T) => boolean,
  config: Partial<TreeHelperConfig> = {},
): T[]

参数说明

参数值类型参数值说明
treeany要过滤的元素树。
funcFn应用于每个元素的过滤函数。
configPartial<TreeHelperConfig>可选的配置对象,用于自定义树助手的行为。

示例

vue
<script setup>
import { ikTree } from  'iking-utils'
const tree = [
  {
    id: 1,
    name: '节点 1',
    children: [
      {
        id: 2,
        name: '节点 2',
        children: [
          {
            id: 3,
            name: 'Node 3',
          },
          {
            id: 4,
            name: 'Node 4',
          },
        ],
      },
      {
        id: 5,
        name: '节点 5',
      },
    ],
  },
  {
    id: 6,
    name: '节点 6',
  },
];

// 定义条件函数
function filterNodesWithName(node: any) {
  return node.name.includes('节点')
}

// 调用 filter 函数
const filteredNodes = ikTree.filter(tree, filterNodesWithName);

console.log(filteredNodes);
// Output: [
//   { id: 1, name: '节点 1', children: [
//     { id: 2, name: '节点 2', children: []},
//     { id: 5, name: '节点 5', children: undefined }
//   ]},
//   { id: 6, name: '节点 6', children: undefined}
// ]
</script>

treeMap

提取指定结构的树 通过对树状数据结构中的每一项应用转换函数来生成一个新的数组。

包含转换项的新数组

script
treeMap<T = any>(treeData: T[], opt: { children?: string; conversion: Fn }): T[]

参数说明

参数值类型参数值说明
treeDataT[]要过滤的元素树。
opt{ children?: string; conversion: Fn }一个选项对象
opt.childrenstring每个项的子数组的属性名。默认为“children”
opt.conversionfunction要应用于每个项目的转换函数。

示例

vue
<script setup>
import { ikTree } from  'iking-utils'
const treeData = [
  {
    id: 1,
    name: 'Parent 1',
    children: [
      {
        id: 2,
        name: 'Child 1.1',
        children: [
          {
            id: 3,
            name: 'Grandchild 1.1.1',
            children: []
          },
          {
            id: 4,
            name: 'Grandchild 1.1.2',
            children: []
          }
        ]
      },
      {
        id: 5,
        name: 'Child 1.2',
        children: []
      }
    ]
  },
  {
    id: 6,
    name: 'Parent 2',
    children: [
      {
        id: 7,
        name: 'Child 2.1',
        children: []
      }
    ]
  }
];

// 定义转换函数
function convertData(data) {
  return {
    id: data.id,
    label: data.name
  };
}

// 调用treeMap
const mappedTree = ikTree.treeMap(treeData, { children: 'children', conversion: convertData });

console.log(mappedTree);
// Output:  [
//   {
//     id: 1,
//     label: 'Parent 1',
//     children: [
//       {
//         id: 2,
//         label: 'Child 1.1',
//         children: [
//           {
//             id: 3,
//             label: 'Grandchild 1.1.1',
//             children: []
//           },
//           {
//             id: 4,
//             label: 'Grandchild 1.1.2',
//             children: []
//           }
//         ]
//       },
//       {
//         id: 5,
//         label: 'Child 1.2',
//         children: []
//       }
//     ]
//   },
//   {
//     id: 6,
//     label: 'Parent 2',
//     children: [
//       {
//         id: 7,
//         label: 'Child 2.1',
//         children: []
//       }
//     ]
//   }
// ]
</script>

treeMapEach

提取指定结构的树 提取指定结构的树

总的来说,该函数递归地映射树结构中的每个节点,将转换函数应用于每个节点,并保留父节点和子节点之间的层次关系

script
treeMapEach(
  data: any,
  { children = 'children', conversion }: { children?: string; conversion: Fn },
)

参数说明

参数值类型参数值说明
treeDataT[]要过滤的元素树。
opt{ children?: string; conversion: Fn }一个可选的对象参数
opt.childrenstring每个项的子数组的属性名。默认为“children”
opt.conversionfunction要应用于每个项目的转换函数。

示例

vue
<script setup>
import { ikTree } from  'iking-utils'
const treeData = [
  {
    id: 1,
    name: 'Parent 1',
    children: [
      {
        id: 2,
        name: 'Child 1.1',
        children: [
          {
            id: 3,
            name: 'Grandchild 1.1.1',
            children: []
          },
          {
            id: 4,
            name: 'Grandchild 1.1.2',
            children: []
          }
        ]
      },
      {
        id: 5,
        name: 'Child 1.2',
        children: []
      }
    ]
  },
  {
    id: 6,
    name: 'Parent 2',
    children: [
      {
        id: 7,
        name: 'Child 2.1',
        children: []
      }
    ]
  }
];

// 定义返回函数
function convertData(data, opt) {
  return data.map((item: any) => ikTree.treeMapEach(item, opt));
}
// 定义转换函数
function convertData(data) {
  return {
    id: data.id,
    label: data.name
  };
}

// 调用treeMap
const mappedTree = convertData(treeData, { children: 'children', conversion: convertData });

console.log(mappedTree);
// Output:  [
//   {
//     id: 1,
//     label: 'Parent 1',
//     children: [
//       {
//         id: 2,
//         label: 'Child 1.1',
//         children: [
//           {
//             id: 3,
//             label: 'Grandchild 1.1.1',
//             children: []
//           },
//           {
//             id: 4,
//             label: 'Grandchild 1.1.2',
//             children: []
//           }
//         ]
//       },
//       {
//         id: 5,
//         label: 'Child 1.2',
//         children: []
//       }
//     ]
//   },
//   {
//     id: 6,
//     label: 'Parent 2',
//     children: [
//       {
//         id: 7,
//         label: 'Child 2.1',
//         children: []
//       }
//     ]
//   }
// ]
</script>

listToTree

将节点的平面列表转换为树结构

返回转换成树结构的节点列表。

script
listToTree
  <T extends { 
    __nodekey?: number, 
    config?: TreeHelperConfig, 
    [key:string]: any }>
  (list: T[], config: Partial<TreeHelperConfig> = {}): T[]

参数说明

参数值类型参数值说明
listT[]节点的平面列表
configPartial<TreeHelperConfig>一个可选的对象参数

示例

vue
<script setup>
import { ikTree } from  'iking-utils'
const treeList = [
  {
    id: 1,
    label: 'Parent 1'
    parentId: null
  },
  {
    id: 2,
    label: 'Child 1.1',
    parentId: 1
  },
  {
    id: 213,
    label: 'Grandchild 1.1.1',
    parentId: 2
  },
  {
    id: 214,
    label: 'Grandchild 1.1.2',
    parentId: 2
  },
  {
    id: 65,
    label: 'Child 1.2',
    parentId: 6
  },
  {
    id: 67,
    label: 'Child 2.1',
    parentId: 6
  },
  {
    id: 6,
    label: 'Parent 2',
    parentId: null
  }
];


// 定义树形结构的配置
const config = { 
  pid: 'parentId', 
  id: 'id', 
}
// 调用listToTree
const treeData = ikTree.listToTree(treeList, config);

console.log(treeData);
// Output:
// [{
// 	id: 1,
// 	label: "Parent 1",
// 	children: [{
// 		id: 2,
// 		label: "Child 1.1",
// 		parentId: 1,
// 		children: [{
// 			id: 213,
// 			label: "Grandchild 1.1.1",
// 			parentId: 2
// 		}, {
// 			id: 214,
// 			label: "Grandchild 1.1.2",
// 			parentId: 2
// 		}]
// 	}]
// }, {
// 	id: 6,
// 	label: "Parent 2",
// 	children: [{
// 		id: 65,
// 		label: "Child 1.2",
// 		parentId: 6
// 	}, {
// 		id: 67,
// 		label: "Child 2.1",
// 		parentId: 6
// 	}]
// }]
</script>
vue
<script setup>
import { ikTree } from  'iking-utils'
const treeList = [
  {
    id: 1,
    label: 'Parent 1'
    parentId: null
  },
  {
    id: 2,
    label: 'Child 1.1',
    parentId: 1
  },
  {
    id: 213,
    label: 'Grandchild 1.1.1',
    parentId: 2
  },
  {
    id: 214,
    label: 'Grandchild 1.1.2',
    parentId: 2
  },
  {
    id: 65,
    label: 'Child 1.2',
    parentId: 6
  },
  {
    id: 67,
    label: 'Child 2.1',
    parentId: 6
  },
  {
    id: 6,
    label: 'Parent 2',
    parentId: null
  }
];


// 定义树形结构的配置
const config = { 
  pid: 'parentId', 
  id: 'id', 
  sort: 'id', 
  needSort: true 
}
// 调用listToTree
const treeData = ikTree.listToTree(treeList, config);

console.log(treeData);
// Output: 
// [{
// 	"id": 1,
// 	"label": "Parent 1",
// 	"children": [{
// 		"id": 2,
// 		"label": "Child 1.1",
// 		"parentId": 1,
// 		"children": [{
// 			"id": 213,
// 			"label": "Grandchild 1.1.1",
// 			"parentId": 2,
// 			"__nodekey": 111
// 		}, {
// 			"id": 214,
// 			"label": "Grandchild 1.1.2",
// 			"parentId": 2,
// 			"__nodekey": 112
// 		}],
// 		"__nodekey": 11
// 	}],
// 	"__nodekey": 1
// }, {
// 	"id": 6,
// 	"label": "Parent 2",
// 	"children": [{
// 		"id": 65,
// 		"label": "Child 1.2",
// 		"parentId": 6,
// 		"__nodekey": 21
// 	}, {
// 		"id": 67,
// 		"label": "Child 2.1",
// 		"parentId": 6,
// 		"__nodekey": 22
// 	}],
// 	"__nodekey": 2
// }]
</script>

setListNodeKey

将节点的平面列表转换为树结构

返回转换成树结构的节点列表。

script
setListNodeKey<T extends { 
  __nodekey?: number, 
  children?: T[], 
  [key: string]: any 
  }>(result: T[] | T, ind: string | number = '', conf: TreeHelperConfig)

参数说明

参数值类型参数值说明
listT[]节点的平面列表
configPartial<TreeHelperConfig>一个可选的对象参数

示例

vue
<script setup>
import { ikTree } from  'iking-utils'
// 定义树形结构的配置
const config = {
  sort: 'id' // Sorting property
};

// 定义节点的初始平面列表
const nodeList = [
  { id: 1, name: 'Node 1', children: [
    { id: 2, name: 'Node 1.1' },
    { id: 3, name: 'Node 1.2', children: [
      { id: 4, name: 'Node 1.2.1' },
      { id: 5, name: 'Node 1.2.2' }
    ]}
  ]},
  { id: 6, name: 'Node 2' }
];

// 调用setListNodeKey函数来设置节点密钥
ikTree.setListNodeKey(nodeList, '', config);

// 输出带有指定键的修改后的nodeList
console.log(nodeList);
// Output: 
// [
//   { id: 1, name: 'Node 1', __nodekey: 1, children: [
//     { id: 2, name: 'Node 1.1', __nodekey: 11 },
//     { id: 3, name: 'Node 1.2', __nodekey: 12, children: [
//       { id: 4, name: 'Node 1.2.1', __nodekey: 121 },
//       { id: 5, name: 'Node 1.2.2', __nodekey: 122 }
//     ]}
//   ]},
//   { id: 6, name: 'Node 2', __nodekey: 2 }
// ]
</script>

treeToList

将树结构转换为平面列表。

返回的转换后的平面列表。

script
treeToList<T = any>
  (tree: any, config: Partial<TreeHelperConfig> = {}): T

参数说明

参数值类型参数值说明
treeany要转换的树结构。
configPartial<TreeHelperConfig>配置对象

示例

vue
<script setup>
import { ikTree } from  'iking-utils'
// 定义树形结构
const tree = [
  {
    id: 1,
    name: 'Parent 1',
    children: [
      {
        id: 2,
        name: 'Child 1.1',
      },
      {
        id: 3,
        name: 'Child 1.2',
        children: [
          {
            id: 4,
            name: 'Grandchild 1.2.1',
          },
          {
            id: 5,
            name: 'Grandchild 1.2.2',
          },
        ],
      },
    ],
  },
  {
    id: 6,
    name: 'Parent 2',
  },
];

// 调用treeToList函数将树转换为平面列表
const flatList = ikTree.treeToList(tree);

// 输出转换后的平面列表
console.log(flatList);
// Output:  
// [
//   { id: 1, name: 'Parent 1' },
//   { id: 2, name: 'Child 1.1' },
//   { id: 3, name: 'Child 1.2' },
//   { id: 4, name: 'Grandchild 1.2.1' },
//   { id: 5, name: 'Grandchild 1.2.2' },
//   { id: 6, name: 'Parent 2' }
// ]
</script>

arrayToMapTree

接受一个节点数组,并将其转换为一个映射树结构。

数组中的每个节点由一个唯一的id表示。该函数创建一个映射其中键是节点id,值是节点本身。函数遍历数组中的每个节点并检查它是否有父节点。

如果是,则使用parentId从映射中检索父节点。如果父母节点存在,当前节点被添加到父节点的子数组。

最后,函数返回映射树结构。

vue
  <script>
    export interface Node {
      id: number;
      name: string;
      parentId?: number | null;
      children?: Node[]; 
    }
    export const arrayToMapTree = (nodes: Node[]): Map<number, Node> => {
      const map = new Map<number, Node>();
      nodes.forEach(node => map.set(node.id, node));

      nodes.forEach(node => {
        if (node.parentId !== undefined && node.parentId !== null) {
          const parent = map.get(node.parentId);
          if (parent) {
            parent.children = parent.children || [];
            parent.children.push(node);
          }
        }
      });

      return map;
    }
  </script>

参数说明

参数值类型参数值说明
nodesNode[]一个要转换成地图树结构的节点数组
vue
<script setup>
import { ikTree } from  'iking-utils'

// 定义Node接口
interface Node {
  id: number;
  parentId?: number | null;
  children?: Node[];
  // 其他属性字段...
}

// 定义节点数组
const nodes: Node[] = [
  { id: 1, parentId: null },
  { id: 2, parentId: 1 },
  { id: 3, parentId: 1 },
  { id: 4, parentId: 2 },
  { id: 5, parentId: 2 },
  { id: 6, parentId: 3 },
];

// 调用arrayToMapTree函数将数组转换为映射树结构
const mapTree = ikTree.arrayToMapTree(nodes);

// 输出映射树结构
console.log(mapTree);
// outPut
// Map(6) {
//   1 => { id: 1, parentId: null, children: [ [Object], [Object] ] },
//   2 => { id: 2, parentId: 1, children: [ [Object], [Object] ] },
//   3 => { id: 3, parentId: 1, children: [ [Object] ] },
//   4 => { id: 4, parentId: 2 },
//   5 => { id: 5, parentId: 2 },
//   6 => { id: 6, parentId: 3 }
// }
</script>

treeTraverse

递归遍历树,并在每次遍历时执行callback函数

vue
<script lang="ts" setup>
  type TTraverse = {
    <T>(tree: T): void;
    <T>(tree: T, callback?: Function): void;
    <T>(tree: T, key?: string | Function, callback?: Function): void;
  }

  interface TreeNode<T> {
    [key: string]: T | TreeNode<T>[];
  }

  const treeTraverse = 
    (<T>(tree: TreeNode<T>, key: string | Function = 'children', callback?: Function) => {
    const _key: string = paramType.isString(key) ? key : 'children'
    const _callback = paramType.isFunction(key) ? key : (callback ?? null)
    _callback && _callback(tree);
    if (tree[_key]) {
      const _tree = paramType.isArray(tree[_key]) ? tree[_key] : [tree[_key]];
      (_tree as TreeNode<T>[]).forEach(child => {
        treeTraverse(child, callback);
      });
    }
  }) as TTraverse
</script>

参数说明

参数值类型默认值参数值说明
treeTreeNode<T>-一个要转换成地图树结构的节点数组
keyString | Function'children'一个要转换成地图树结构的节点数组
callbackFunction-(可选参数)回调函数
vue
<script setup>
import { ikTree } from  'iking-utils'

interface Person {
  name: string
  children?: Person[]
}

const tree: Person = {
  name: 'Alice',
  children: [
    {
      name: 'Bob',
      children: [
        {
          name: 'Charlie'
        },
        {
          name: 'Dave'
        }
      ]
    },
    {
      name: 'Eve'
    }
  ]
}

// 定义要在每个节点上执行的回调函数
function printName(person: Person) {
  console.log(person.name)
  //outPut: Alice
  //outPut: Bob
  //outPut: Charlie
  //outPut: Dave
  //outPut: Eve
}

// 用树和回调函数调用treeTraverse函数
ikTree.treeTraverse(tree, 'children', printName)
</script>