如何在JavaScript中从带有缩进的平面列表构建树?
面对这个问题,我总是很挣扎,这需要一些认真的工作。我目前正在尝试解决这个问题,可能需要几天时间。想看看你是否有一个系统或简单的方法来解决这个问题 基本上,假设您有一个DOM节点的平面列表,以15px的步长填充左缩进。在视觉上,它形成了一个类似于文件浏览器的树。但在DOM的结构上,它是作为一个平面列表实现的。然后如何遍历列表并构建树如何在JavaScript中从带有缩进的平面列表构建树?,javascript,algorithm,tree,Javascript,Algorithm,Tree,面对这个问题,我总是很挣扎,这需要一些认真的工作。我目前正在尝试解决这个问题,可能需要几天时间。想看看你是否有一个系统或简单的方法来解决这个问题 基本上,假设您有一个DOM节点的平面列表,以15px的步长填充左缩进。在视觉上,它形成了一个类似于文件浏览器的树。但在DOM的结构上,它是作为一个平面列表实现的。然后如何遍历列表并构建树 <div style='padding-left: 0px'>A</div> <div style='padding-left: 15p
<div style='padding-left: 0px'>A</div>
<div style='padding-left: 15px'>AA</div>
<div style='padding-left: 15px'>AB</div>
<div style='padding-left: 30px'>ABA</div>
<div style='padding-left: 30px'>ABB</div>
<div style='padding-left: 45px'>ABBA</div>
<div style='padding-left: 45px'>ABBB</div>
<div style='padding-left: 45px'>ABBC</div>
<div style='padding-left: 30px'>ABC</div>
<div style='padding-left: 15px'>AC</div>
<div style='padding-left: 0px'>B</div>
<div style='padding-left: 0px'>C</div>
...
你是怎么做到的?我迷路了:
let tree = []
let path = [0]
let items = list('div')
items.forEach(item => {
let left = parseInt(item.style[`padding-left`] || 0) % 15
let set = tree
let p = path.concat()
while (left) {
let x = p.shift()
set[x] = set[x] || { children: [] }
set = set[x].children
left--
}
})
function list(s) {
return Array.prototype.slice.call(document.querySelectorAll(s))
}
这是一个堆栈,因为它是连续的。像这样的 我们假设文件夹结构已完全“展开”,因此每个文件夹的父文件夹(最低文件夹除外,父文件夹是根文件夹)必须在当前文件夹之前进行检查。父级还必须具有较低的“左填充”赋值
ptrs
是一个堆栈,我们在其中附加对下一个检查文件夹的引用。堆栈顶部(末端)的文件夹是我们检查的最后一个文件夹。如果堆栈顶部的文件夹具有大于或等于“padding left”的赋值,则它们不可能是当前文件夹的父文件夹;在当前文件夹之后,我们不可能有更多的子文件夹,所以我们会删除(弹出)它们,直到找到最后一个“剩余填充”较低的文件夹
函数getData(s){
常量左=+s.match(/\d+/)[0];
常数title=s.match(/[A-Z]+/)[0];
返回[左,标题];
}
职能f(部门){
常数树={
标题:'根',
儿童:[]
};
常量ptrs=[[0,树]];//堆栈
for(让str of divs){
const[left,title]=getData(str);
while(ptrs.length&&ptrs[ptrs.length-1][0]>=左)
ptrs.pop();
父项=ptrs.length?ptrs[ptrs.length-1][1]:树;
const obj={title:title,子项:[]};
父.子.推(obj);
ptrs.推送([左,obj]);
}
回归树;
}
var divs=[
“A”,
“AA”,
“AB”,
“ABA”,
“ABB”,
“阿巴”,
“ABBB”,
“ABBC”,
“ABC”,
“AC”,
“B”,
“C”
]
控制台日志(f(divs))代码>有趣的练习。这是另一种比以前的解决方案更详细的方法,但也适用于dom节点,而不是字符串html
constbuildtree=(选择器)=>{
常量元素=[…document.queryselectoral(选择器)]
.map((el,i)=>({el,title:el.textContent,idx:i,inset:parseInt(el.style.paddingLeft)});
const getChildren=({inset:pInset,idx:start})=>{
const nextParentIdx=elems.findIndex(({inset,idx},i)=>inset start);
常量描述=元素切片(开始,下一个Rentidx+1)
.filter(({inset})=>inset pInset==15);
返回描述图(getItem);
}
常量getItem=(o)=>{
返回{title:o.title,children:getChildren(o)}
}
返回elems.filter(({inset})=>!inset.map(getItem)
}
log(JSON.stringify(buildTree('div'),null,4))
。作为控制台包装{最大高度:100%!重要;顶部:0;}
A
AA
AB
阿巴
神甫
阿巴
缩写
ABBC
基础知识
自动控制
B
C
工作起来很有魅力!你能解释一下一般的技术吗?对我来说,它仍然像魔术一样:)也许可以在循环中遍历代码行以及它们背后的推理。@LancePollard当然。我补充了一个解释。如果还有什么需要澄清的,请告诉我。当然,我只使用字符串HTML作为示例。我当时正在打手机,而且我不想把它弄糟:)
let tree = []
let path = [0]
let items = list('div')
items.forEach(item => {
let left = parseInt(item.style[`padding-left`] || 0) % 15
let set = tree
let p = path.concat()
while (left) {
let x = p.shift()
set[x] = set[x] || { children: [] }
set = set[x].children
left--
}
})
function list(s) {
return Array.prototype.slice.call(document.querySelectorAll(s))
}