【问题标题】:DOM Tree reduce using RAMDA使用 RAMDA 减少 DOM 树
【发布时间】:2016-09-30 08:18:23
【问题描述】:

我想在浏览器中遍历 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)

但我没有看到简单的减少...有什么想法吗?

谢谢,

【问题讨论】:

    标签: javascript functional-programming ramda.js


    【解决方案1】:

    您可以解决此问题的一种方法是为 Node 实例创建一个包装器类型,并使用 Ramda 可以调度到的 reduce 方法,允许您汇总 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
    }, []))
    

    您可以在下面的 sn-p 中看到一个示例。

    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>

    【讨论】:

      猜你喜欢
      • 2019-06-15
      • 2022-01-25
      • 2013-04-23
      • 2016-03-29
      • 1970-01-01
      • 1970-01-01
      • 2016-04-01
      • 2020-12-08
      • 2013-04-21
      相关资源
      最近更新 更多