树形数据处理工具 treelike-helper 用法说明
基于之前的树形结构数据查找某个 key 的路径的函数为核心,我写了一个对树形(嵌套)数据处理的工具 treelike-helper
下面讲一下这个工具都有什么功能:
npm install treelike-helper
API
mapTreeData
类似 map,可以对树中每一个节点的数据进行操作
使用:
import { mapTreeData } from 'treelike-helper'
const treeData = [
{ id: '1', title: '1' },
{ id: '2', title: '2', children: [{ id: '2-1', title: '2-1' }] },
]
mapTreeData(treeData, item => {
if (item.id === '2-1') {
item.isLeaf = true
}
return {
...item,
name: item.title,
key: item.id,
}
})
// [
// { id: '1', title: '1', name: '1', key: '1' },
// {
// id: '2',
// title: '2',
// children: [{ id: '2-1', title: '2-1', isLeaf: true, name: '2-1', key: '2-1' }],
// name: '2',
// key: '2',
// },
// ]
filterTreeData
类似 filter,需要注意的是,像下面示例这种情况,当父节点不满足时,子节点即使满足也会被筛选掉
import { filterTreeData } from 'treelike-helper'
const treeData = [
{ id: '1', title: '1', hasPermission: true },
{ id: '2', title: '2' },
{
id: '3',
title: '3',
hasPermission: true,
children: [
{ id: '3-1', title: '3-1' },
{ id: '3-2', title: '3-2', hasPermission: true },
{ id: '3-3', title: '3-3', hasPermission: false },
],
},
{
id: '4',
title: '4',
hasPermission: false,
children: [
{ id: '4-1', title: '4-1' },
{ id: '4-2', title: '4-2', hasPermission: true },
],
},
]
filterTreeData(treeData, (node) => node.hasPermission)
// [
// { id: '1', title: '1', hasPermission: true },
// {
// id: '3',
// title: '3',
// hasPermission: true,
// children: [{ id: '3-2', title: '3-2', hasPermission: true }],
// },
// ]
mapFilterTreeData
map 和 filter 的结合,需要注意的是顺序不能变,第二个参数同 filterTreeData,第三个参数同 mapTreeData,且第三个参数时拿到的数据是已经筛选后的数据
import { mapFilterTreeData } from 'treelike-helper'
mapFilterTreeData(
[
{ id: '1', title: '1', hasPermission: true },
{ id: '2', title: '2' },
{
id: '3',
title: '3',
hasPermission: true,
children: [
{ id: '3-1', title: '3-1' },
{ id: '3-2', title: '3-2', hasPermission: true },
{ id: '3-3', title: '3-3', hasPermission: false },
],
},
],
item => item.hasPermission,
item => ({ ...item, subTitle: 'already filter data' })
)
// [
// {
// id: '1',
// title: '1',
// hasPermission: true,
// subTitle: 'already filter data',
// },
// {
// id: '3',
// title: '3',
// hasPermission: true,
// subTitle: 'already filter data',
// children: [
// {
// id: '3-2',
// title: '3-2',
// hasPermission: true,
// subTitle: 'already filter data',
// },
// ],
// },
// ]
findKeyPath
查找 keyPath(Array)
findKeyPath([{ key: 1, children: [{key: 2}] }], 2)
// [0, 'children', 0]
findData
根据targetKey查找树中的某个节点
findData([{key: 1, children: [{ key: 2, children: [{ key: 3 }] }] }], 3)
// { key: 3 }
findParentData
根据targetKey查找父节点数据
const treeData = [
{
key: '1', children: [
{ key: '1-1' },
{
key: '1-2', children: [
{ key: '1-2-1' }
]
}
]
}
]
findParentData(treeData, '1-2-1')
// { key: '1-2', children: [{ key: '1-2-1' }] }
findSearchData
根据search查找所有相关的数据,但是并不是平铺的数据,而是会一直延伸到根节点,通常用于树形搜索
const treeData = [
{ key: '1', title: 'layer1' },
{
key: '2',
title: '2',
children: [
{ key: '2-1', title: '2-1' },
{
key: '2-2',
title: '2-2',
children: [{ key: '2-2-1', title: '2-2-1' }],
},
{
key: '2-3',
title: 'layer2-3',
},
],
},
];
findSearchData(treeData, 'lay')
// [
// { key: '1', title: 'layer1' },
// { key: '2', title: '2', children: [{ key: '2-3', title: 'layer2-3' }] },
// ]
addData
根据targetKey向该节点下添加数据
const treeData = [
{ key: '1' },
{
key: '2',
children: [
{ key: '2-1' },
],
},
];
const newTreeData1 = addData(treeData, '1', { key: '1-1', title: '1-1' })
// [
// { key: '1', children: [{ key: '1-1', title: '1-1' }] },
// { key: '2', children: [{ key: '2-1' }] },
// ]
const newTreeData2 = addData(treeData, '2-1', { key: '2-1-2' })
// [
// { key: '1' },
// { key: '2', children: [{ key: '2-1', children: [{ key: '2-1-2' }] }] },
// ]
deleteData
根据targetKey删除该节点(包括子节点)的数据,除此之外还有一个选项是deleteEmptyParent,当删除后父节点下的子节点为空,就删除子数组。
const treeData = [
{ key: 1 },
{ key: 2, children: [{ key: 22, children: [{ key: 33 }] }] },
];
deleteData(treeData, 2)
// [ { "key": 1 } ]
deleteData(treeData, 33)
// [
// { key: 1 },
// { key: 2, children: [{ key: 22, children: [] }] }
// ]
deleteData(treeData, 33, { deleteEmptyParent: true })
// [
// { key: 1 },
// { key: 2, children: [{ key: 22 }] }
// ];
updateData
根据targetKey修改节点数据
const treeData = [
{ key: 1 },
{ key: 2, children: [{ key: 22, children: [{ key: 33 }] }] },
];
updateData(treeData, 33, { key: 33, edit: true })
// [
// { key: 1 },
// { key: 2, children: [{ key: 22, children: [{ key: 33, edit: true }] }] }
// ];
updateData(treeData, 33, node => {
return {
...node,
edit: true,
};
})
// [
// { key: 1 },
// { key: 2, children: [{ key: 22, children: [{ key: 33, edit: true }] }] }
// ];
updateThroughData
根据targetKey,修改该节点的所有途经父节点,默认不修改自身,添加includeSelf可以修改自身
const treeData = [
{ key: '1', children: [{ key: '1-1', children: [{ key: '1-1-1' }] }, { key: '1-2' }] },
]
updateThroughData(treeData, '1-1-1', node => {
return { ...node, edited: true }
})
// [
// {
// key: '1',
// children: [{ key: '1-1', children: [{ key: '1-1-1' }], edited: true }, { key: '1-2' }],
// edited: true,
// },
// ]
updateThroughData([{ key: 1, children: [{ key: 11 }] }], 11, node => {
return { ...node, edited: true }
}, { includeSelf: true })
// [
// { key: 1,
// children: [{ key: 11, edited: true }],
// edited: true
// }
// ]
getFieldValues
得到树形数据中所有给定field的值的Array,也可以使用在某些场景例如:想获得所有字段open为true的节点的key
const treeData = [
{ key: '1', children: [{ key: '11' }] },
{ key: '2', children: [{ key: '21', open: true }] },
{ key: '3', children: [{ key: '31' }] },
]
getFieldValues(treeData, 'key')
// ['1', '11', '2', '21', '3', '31']
getFieldValues(treeData, node => node.open ? node.key : null).filter(Boolean)
// ['21']
getFieldValueSet
和getFieldValue基本一直,只是返回的是去重的Set类型
calculateLeafCount
计算树形数据的叶子节点数量,只有没有子数据的节点才算叶子节点
const treeData = [
{
key: '1', title: 'parent 1', children: [
{ key: '1-1', title: 'leaf 1-1' },
{ key: '1-2', title: 'leaf 1-2' },
]
},
{
key: '2', title: 'parent 2', children: [
{ key: '2-1', title: 'leaf 2-1' },
{ key: '2-2', title: 'leaf 2-2' },
]
},
]
calculateLeafCount(treeData)
// 4
countNestedLayers
计算树形数据深度(最大值)
countNestedLayers([])
// 0
countNestedLayers([{ key: '1', title: '1' }])
// 1
countNestedLayers([{ key: '1', children: [{ key: '1-1' }] }])
// 2
countNestedLayers([
{ key: 1, children: [{ key: 11 }] },
{ key: 2, children: [{ key: 21, children: [{ key: 211 }] }] }
])
// 3
说明
- 所有的这些方法都不会改变原数据
- 如果数据的唯一值并不是"key",子数据不是"children",大多数函数都可以传递一个options,来指定子数组的keyName,或者是查询定位的keyName,例如:
findData([{id: 1, subs: [{ id: 2, subs: [{ id: 3 }] }] }], 3, {keyName: 'id', childrenKeyName: 'subs'})
// { id: 3 }
具体情况可以看详细文档 treelike-helper