树形结构数据查找某个 key 的路径

需求

假设有一个树形数据treeData

javascript 复制代码
const treeData = [
    { key: 1, title: 'node1'},
    { key: 2, title: 'node2', children: 
        [
            { key: 3, title: 'node3', children: 
                [
                    { key: 4, title: 'node4' }
                ]
            }
         ]
     }
]

大概就是这么个数据,现在给出一个 key,可以得到该节点的路径。

例如给出的 key 为4,那么期望得到 [1, 'children', 0, 'children', 0],奇数部分代表 children 中的 index,偶数部分固定是 'children',可以看到得到这个 path 数组后可以直接拿到这个节点的数据,比如使用 lodash 中的 get 方法,或者循环 path 取值。

思路

直接看一下完整代码

javascript 复制代码
function findKeyPath(treelikeData, targetKey, childrenKey = 'children') {
  const recursiveSearch = (_treelikeData = []) => {
    let path = [];
    const hasKey = _treelikeData.some((dataItem, index) => {
      if (dataItem.key === targetKey) {
        path.push(index);
        return true;
      }
      if (Array.isArray(dataItem[childrenKey])) {
        const searchResult = recursiveSearch(dataItem[childrenKey]);
        if (searchResult.hasKey) {
          path = [...path, index, childrenKey, ...searchResult.path];
        }
        return searchResult.hasKey;
      }
      return false;
    });
    return { hasKey, path };
  };

  const searchResult = recursiveSearch(treelikeData);
  return searchResult.path;
}

我的思路是这样的,先写一个递归的搜索函数recursiveSearch,这个函数会返回hasKey 和 path 两个数据,path 是最终要得到的路径,hasKey是用来判断是否找到了 key。

用Array 的 some 函数来遍历数据的原因是,当返回了 true 之后,遍历会立即停止,这样能节省些开销,且 some 的返回结果就是 true 或 false,正好可以用来判断是否找到了。

在查找判断是否有 key 时,先排除 2 种边界情况:

  1. 如果dataItem.key === targetKey,就直接返回 true 并且把该数据的 index 添加进 path 中,这是已经递归到最末端的情况了。
  2. 排除 1 情况后,遍历出来的当前item,没有子数组了,说明这一枝并没有要寻找的数据,直接返回 false

接下来就是需要递归的部分了,此时复杂的情况已经简化了,首先递归查找当前数据的子数组中是否有要查找的数据,就像上面说的那样,递归搜索函数的返回结果是path和 hasKey,这时候判断一下hasKey是true还是false,如果是true的话,就将子数组返回的path和当前的path合并(中间加上当前的index和 'children')

使用

javascript 复制代码
const keyPath = findKeyPath(treeData, '4')
//  [1, 'children',  0, 'children',  0]

ps: 其实如果数据是后端传来的,可能返回的是 [{ id: 1, children: [] }] 这样的数据,这部分取值时修改成 dataItem.key,或者定义一个参数 dataItem[keyName]即可

相关推荐
嘉琪0012 分钟前
vue3+ts面试题(一)JSX,SFC
前端·javascript·react.js
何贤15 分钟前
🪐 行星科技概念官网!Hero Section 回归!(Three.js ✨)
前端·javascript·three.js
前端拿破轮18 分钟前
ReactNative从入门到性能优化(一)
前端·react native·客户端
码界奇点28 分钟前
Java Web学习 第1篇前端基石HTML 入门与核心概念解析
java·前端·学习·xhtml
云枫晖34 分钟前
Webpack系列-开发环境
前端·webpack
Rverdoser39 分钟前
制作网站的价格一般由什么组成
前端·git·github
拉不动的猪39 分钟前
深入理解 JavaScript 中的静态属性、原型属性与实例属性
前端·javascript·面试
linda26181 小时前
链接形式与跳转逻辑总览
前端·javascript
怪可爱的地球人1 小时前
骨架屏
前端
用户677847150621 小时前
前端将html导出为word文件
前端