问题
现有一个树形结构的菜单,支持无限的嵌套层级,需要根据用户点击的某个子菜单,获取到这个子菜单所在节点的路径,类似于面包屑效果。
一个合格的树形菜单数据结构
const menu = [{
id:'1',
label: '一级 1',
children: [{
id:'11',
label: '二级 1-1',
children: [{
id:'111',
label: '三级 1-1-1'
}]
}]
}, {
id:'2',
label: '一级 2',
children: [{
id:'21',
label: '二级 2-1',
children: [{
id:'211',
label: '三级 2-1-1'
}]
}, {
id:'22',
label: '二级 2-2',
children: [{
id:'221',
label: '三级 2-2-1'
}]
}]
}, {
id:'3',
label: '一级 3',
children: [{
id:'31',
label: '二级 3-1',
children: [{
id:'311',
label: '三级 3-1-1'
}]
}, {
id:'32',
label: '二级 3-2',
children: [{
id:'321',
label: '三级 3-2-1'
}]
}]
}]
解决方案
思路:
递归整个树形菜单,记录下每次循环时候的当前路径名称,匹配到之后再把所有节点名称拼接起来。
其中有一个关键处理点是每次循环到同级数组,需要重新开始记录路径,否则会出现路径重复的情况
代码:
/**
* @param {array[][]} data 整个菜单数组
* @param {object[][]} v 当前节点对象
* @return {string[]} 当前节点对象路径
*/
function findPath(data, v){
var find = false; //找到id后标记,结束递归
var paths = [];
findId(data, v.id);
return paths.join('/');
function findId(root, vid) {
var currentPathsLength = paths.length;
root.forEach((ele, i, root) => {
// 后面不再循环找了
if (find) {
return
}
// 每次循环到同级数组,重新开始记录路径
paths = paths.slice(0,currentPathsLength);
paths.push(ele.label)
// 找到即返回
if (ele.id === vid) {
find = true;
return;
} else if (Array.isArray(ele.children) && ele.children.length > 0) { //有子节点继续寻找
return findId(ele.children, vid)
}
});
}
}
在线演示:
See the Pen
zYKeVJe by alex (@dushusir)
on CodePen.