【问题标题】:How to create an array of leaf nodes of an html dom using javascript如何使用javascript创建html dom的叶节点数组
【发布时间】:2014-04-12 22:05:02
【问题描述】:

所以我的问题基本上是这样的,如何使用 javascript 函数返回 html 文档的所有叶节点的数组。稍后我需要对该列表执行操作。例如,如果我有 html:

<body>
   <div>
      <div>
         <p id="para1"></p>
      </div>
   </div>
   <p id="para2"></p>
</body>

那么该函数应该返回一个数组,其中包含 id 为 para1 和 para2 的两个节点。

注意:我希望节点本身不是它们的 ID。虽然给定 id 我可以提取节点,所以这不是一个大问题。

【问题讨论】:

  • 您到底遇到了什么问题?我假设你知道如何调用函数。
  • 我知道我必须使用某种递归,但是如何在该递归函数中更新数组,使其在最终返回时只包含叶节点

标签: javascript arrays dom recursion tree


【解决方案1】:

这是一个简单的函数来获取leafNodes,您可以在其中查看所有节点,包括文本节点(这意味着它永远不会返回包含文本节点的元素):

function getLeafNodes(master) {
    var nodes = Array.prototype.slice.call(master.getElementsByTagName("*"), 0);
    var leafNodes = nodes.filter(function(elem) {
        return !elem.hasChildNodes();
    });
    return leafNodes;
}

工作演示:http://jsfiddle.net/jfriend00/e9D5n/

仅供参考,.filter() 方法需要 IE9。如果您想在早期版本的 IE 中使用此方法,您可以为 .filter() 安装 polyfill 或更改为数组的手动迭代。


如果您不想考虑文本节点,这里有一个版本,因此您正在寻找叶元素,即使它们中有文本节点:

function getLeafNodes(master) {
    var nodes = Array.prototype.slice.call(master.getElementsByTagName("*"), 0);
    var leafNodes = nodes.filter(function(elem) {
        if (elem.hasChildNodes()) {
            // see if any of the child nodes are elements
            for (var i = 0; i < elem.childNodes.length; i++) {
                if (elem.childNodes[i].nodeType == 1) {
                    // there is a child element, so return false to not include
                    // this parent element
                    return false;
                }
            }
        }
        return true;
    });
    return leafNodes;
}

工作演示:http://jsfiddle.net/jfriend00/xu7rv/


还有,这是一个忽略文本节点的递归解决方案:

function getLeafNodes(master) {
    var results = [];
    var children = master.childNodes;
    for (var i = 0; i < children.length; i++) {
        if (children[i].nodeType == 1) {
            var childLeafs = getLeafNodes(children[i]);
            if (childLeafs.length) {
                // if we had child leafs, then concat them onto our current results
                results = results.concat(childLeafs);
            } else {
                // if we didn't have child leafs, then this must be a leaf
                results.push(children[i]);
            }
        }
    }
    // if we didn't find any leaves at this level, then this must be a leaf
    if (!results.length) {
        results.push(master);
    }
    return results;
}

工作演示:http://jsfiddle.net/jfriend00/jNn8H/

【讨论】:

    【解决方案2】:

    我假设“叶节点”是指没有子节点的元素。在这种情况下,您可以获取所有元素,然后遍历每个元素,检查它是否有任何子元素,如果没有,则将其添加到数组中:

    var leaves = new Array();
    var els = document.body.getElementsByTagName("*");
    for (var i = 0; i < els.length; i++) {
        if (els[i].children.length === 0) {
            leaves.push(els[i]);
        }
    }
    

    【讨论】:

      【解决方案3】:

      也许以下会起作用?

      var paraEl=new Array();
      for(i=0;i<document.getElementsByTagName("p").length;i++){
          paraEl[i]=document.getElementsByTagName("p")[i];
      }
      

      但是你知道,document.getElementsByTagName("p") 已经是一个数组了吧?

      【讨论】:

        【解决方案4】:

        所以,您似乎想知道如何将节点添加到数组并返回数组。只需始终从函数返回一个数组并将它们合并:

        function getLeaves(element) {
            if (element.children.length === 0) {
                return [element];
            }
            var leaves = [];
            for (var i = 0, l = element.children.length; i < l; i++) {
                leaves.push.apply(leaves, getLeaves(element.children[i]));
            }
            return leaves;
        }
        

        DEMO

        或者,您可以向下传递一个数组,当元素是一个离开时,它只是将自己添加到其中:

        function getLeaves(element, arr) {
            // create an array if none is passed. This happens in the first call.
            arr = arr || [];
            if (element.children.length === 0) {
                arr.push(element);
            }
            var leaves = [];
            for (var i = 0, l = element.children.length; i < l; i++) {
                getLeaves(element.children[i], arr);
            }
            return arr;
        }
        

        DEMO

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-11-25
          • 2011-09-30
          • 2011-07-12
          • 2020-04-29
          • 1970-01-01
          • 2019-04-07
          • 2015-04-28
          • 2017-02-25
          相关资源
          最近更新 更多