我想在浏览器中走一个DOM树,收集“叶子”的DOM节点,不包含DOM子节点,只包含文本节点。
我想象有一种方法可以用reduce来做到这一点,但对我来说并不明白如何......递归地减少树状结构。
我已经构建了一堆可用的组件......
let nodeFromJQuery = R.invoker(1,'get')(0);
let nodeFromAny = R.ifElse(R.isArrayLike,nodeFromJQuery,R.identity);
let nodeType = R.pipe(nodeFromAny,R.prop('nodeType'));
let children = R.pipe(nodeFromAny,R.prop('childNodes'));
let textNodeType = R.equals(3);
let domNodeType = R.equals(1);
let domNodes = R.map(isDomNode);
let textNodes = R.map(isTextNode);
let isTextNode = R.pipe(nodeType, textNodeType);
let isDomNode = R.pipe(nodeType,domNodeType);
let domChildren = R.pipe(children,R.filter(isDomNode));
isLeaf = R.pipe(domChildren, R.isEmpty);
getNodes = R.filter(R.not(isLeaf));
getLeaves = R.filter(isLeaf)
但我没有看到简单的减少......有什么想法吗?
谢谢,
答案 0 :(得分:2)
您可以采用的一种方法是使用Node
方法为reduce
实例创建一个包装器类型,Ramda可以调度该方法,允许您汇总Node
个实例的整个树
const node = (n) => ({
reduce(f, z) {
switch(n.nodeType) {
case Node.TEXT_NODE:
return f(z, n)
case Node.ELEMENT_NODE:
return R.reduce(
(_z, _n) => node(_n).reduce(f, _z),
f(z, n),
n.childNodes
)
default:
return z // ignore other node types
}
}
})
如果您对收集Text
个节点的列表感兴趣,现在可以通过reduce
选择性地将它们添加到列表中。
const isInterestingTextNode = R.both(
R.propEq('nodeType', Node.TEXT_NODE),
R.propSatisfies(R.complement(R.test(/^\s*$/)), 'textContent')
)
const textNodesOf = R.pipe(node, R.reduce((textNodes, node) => {
if (isInterestingTextNode(node)) textNodes.push(node.textContent)
return textNodes
}, []))
您可以在下面的代码段中看到此示例。
const node = (n) => ({
reduce(f, z) {
switch(n.nodeType) {
case Node.TEXT_NODE:
return f(z, n)
case Node.ELEMENT_NODE:
return R.reduce(
(_z, _n) => node(_n).reduce(f, _z),
f(z, n),
n.childNodes
)
default:
return z // ignore other node types
}
}
})
const isInterestingTextNode = R.both(
R.propEq('nodeType', Node.TEXT_NODE),
R.propSatisfies(R.complement(R.test(/^\s*$/)), 'textContent')
)
const textNodesOf = R.pipe(node, R.reduce((textNodes, node) => {
if (isInterestingTextNode(node)) textNodes.push(node.textContent)
return textNodes
}, []))
console.log(textNodesOf(document.getElementById('root')))

<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.22.1/ramda.min.js"></script>
</head>
<body>
<div id="root">
<div>
<span>foo</span>
</div>
<div>
<span>bar</span>
</div>
</div>
</body>
</html>
&#13;