? ? ? ?工作中不时会遇见对树形结构数据的处理,有时候只需要遍历并获取其中一个属性值就行了(这部分内容请参考笔者的另一篇博客JS遍历树形结构方法),有时候我们则需要根据某些条件去过滤并得到新的树形结构数据。
let nodeList = [ {id: ‘1-1’, children: [{id: ‘1-2-1’}, {id: ‘1-2-2’}]}, {id: ‘2-1’}, {id: ‘3-1’, children: [{id: ‘3-2-1’, children: [{id: ‘3-3-1’}]}]}]
? ? ? ?例如现在我们需要过滤出id为 1-1, 1-2-2, 3-1的数据,并维持原先的层级结构。核心有两点,第一点就是如何递归遍历,第二点就是如何组织新的树形结构,并在后续的遍历中将他传递下去,这里主要是通过参数的引用传递实现的。具体实现如下:
function filterTree (tree = [], map = [], arr = []) { if (!tree.length) return [] for (let item of tree) { if (!map.includes(item.id)) continue let node = {…item, children: []} arr.push(node) if (item.children && item.children.length) filterTree(item.children, map, node.children) } return arr}
控制台打印结果如下:
?这个时候我们发现返回结果已经是我们根据条件过滤后的树形结构了,如果你期望新的树形结构可以过滤掉children为空的情况,我们只需要稍加修改就行,具体实现如下:
function filterTree (tree = [], map = [], parent = {}) { if (!tree.length) return [] for (let item of tree) { if (!map.includes(item.id)) continue let node = {…item} Reflect.deleteProperty(node, ‘children’) if (!parent.children) parent.children = [] parent.children.push(node) if (item.children && item.children.length) filterTree(item.children, map, node) } return parent.children}
?我们可以看到经过这一番调整,已经实现了我们的效果,但是从代码的可读性上来讲,不如第一个直观,所以我们可以封装一个过滤树形结构空数组的方法,这样会更好一点。以下方法仅供参考:
function filterEmptyChildren (arr = [], ret = []) { if (!arr.length) return [] for (let item of arr) { let node = {…item} Reflect.deleteProperty(node, ‘children’) ret.push(node) if (item.children && item.children.length) { node.children = [] filterEmptyChildren(item.children, node.children) } } return ret}
? ? ? ? 有时候我们会对树形结构数据进行不同条件的过滤,?这个时候我们只要把filterTree中的过滤判断抽成一个条件判断的函数就行如下所示:
function filterTree (tree = [], validate = () => {}, param = [], arr = []) { if (!tree.length) return [] for (let item of tree) { if (!validate.apply(null,[item, …param])) continue let node = {…item, children: []} arr.push(node) if (item.children && item.children.length) filterTree(item.children, validate, param, node.children) } return arr}
这个时候我们再写一个过滤函数,依然是根据1-1, 1-2-2, 3-1,过滤得到新的树形结构,过滤函数如下:
function validate (node, map) { return map.includes(node.id)}
?例如再写一个过滤函数用于获取所有一级数据,可以如下:
function getFirstNode (node) { return node.id.length === 3}
?
? ? ? 很容易就得到了我们想要的结果。我们发现当把过滤条件抽离之后,整个filterTree函数就会变得非常灵活,可以自定义不同的validate函数去获取我们希望的树形结构数据。从中我们可以得知灵活的函数来源于灵活的配置,配置则通过入参进入函数,或者有兴趣的朋友可以自己再包个语法糖,这样在调用的时候会更加的直观和简洁。
17623726