3 回答
TA贡献1921条经验 获得超9个赞
使用Array.prototype.flatMap
可以大大降低转换的复杂性 -
如果节点没有值
data-element
,不包含节点;仅包括其子项的结果。
否则(通过归纳)该节点确实具有
data-element
值。将其包含element
在输出中以及该节点的children
.
上面的编号点对应于下面的源评论 -
const root = document.querySelector('[data-element="from-here"]');
const toTree = ({ dataset = {}, children = [] }) =>
dataset.element === undefined // 1
? Array.from(children).flatMap(toTree) // 2
: [ { element: dataset.element // 3
, children: Array.from(children).flatMap(toTree)
}
]
console.log(toTree(root)[0])
<div data-element="from-here">
<div>skip me</div>
<div>
<div data-element="awesome">awesome text</div>
<div data-element="collect-me">
awesome text
<div data-element="also-me">
other text
<div class="but-not-me">...</div>
</div>
</div>
</div>
</div>
请注意,上面我们没有使用querySelectorAll
,因为不需要额外的文档查询。然而,一些明显的改进是 -
将树的形状定义为单独的函数,
branch
为重复任务定义一个助手,
allToTree
const branch = (element = "", children = []) => // 1
({ element, children })
const allToTree = (nodes = []) => // 2
Array.from(nodes).flatMap(toTree)
toTree现在已经摆脱了复杂性。我们的意图很明确,每个功能都易于编写、测试和维护 -
const toTree = ({ dataset = {}, children = [] }) =>
dataset.element === undefined
? allToTree(children)
: [ branch(dataset.element, allToTree(children) ]
TA贡献1865条经验 获得超7个赞
您可以使用Array.filter()它来过滤掉没有属性的元素data-element。
但为了包含包装器 div,您可能data-element还需要添加属性,如下所示。
const root = document.querySelector('[data-element="from-here"]');
function traverse(node) {
if (node.dataset.element) {
return {
element: node.dataset.element,
children: Array.from(node.querySelectorAll(':scope > div'))
.filter(child => {
return child.dataset.element || Array.from(child.children).some(grandChild => grandChild.dataset.element)
// If element has dataset or The child has some children with dataset attribute
})
.map(childNode => traverse(childNode)),
};
} else if (Array.from(node.children).some(child => child.dataset.element)) {
return Array.from(node.querySelectorAll(':scope > div')).filter(child => child.dataset.element).map(childNode => traverse(childNode))
}
}
console.log(traverse(root));
<div data-element="from-here">
<div>skip me</div>
<div>
<div data-element="awesome">awesome text</div>
<div data-element="collect-me">
awesome text
<div data-element="also-me">
other text
<div class="but-not-me">...</div>
</div>
</div>
</div>
</div>
TA贡献1802条经验 获得超6个赞
为什么不使用 usingnode.querySelectorAll(':scope [data-element]')
来代替呢?这将覆盖具有该属性的所有元素,而不仅仅是第一层子元素。
这是一个小提琴: https: //jsfiddle.net/cp21ykng/2/或者我错过了什么?
- 3 回答
- 0 关注
- 116 浏览
添加回答
举报