如何使这个循环递归遍历所有子元素?

43

我有以下代码:

for (var i = 0; i < children.length; i++){
   if(hasClass(children[i], "lbExclude")){
       children[i].parentNode.removeChild(children[i]);
   }
};

我希望它可以遍历所有子孙节点(不仅仅是顶层节点)。我找到了这一行代码,它似乎可以做到:

for(var m = n.firstChild; m != null; m = m.nextSibling) {

但是如果我这样做,我不清楚如何引用当前子元素?我将不再有索引i来确定子元素的位置。有什么建议吗?

谢谢!

更新:

根据答案建议,我现在使用以下内容。这是正确/最有效的方法吗?

function removeTest(child) {
  if (hasClass(child, "lbExclude")) {
    child.parentNode.removeChild(child);
  }
}

function allDescendants(node) {
  for (var i = 0; i < node.childNodes.length; i++) {
    var child = node.childNodes[i];
    allDescendants(child);
    removeTest(child);
  }
}

var children = temp.childNodes;
for (var i = 0; i < children.length; i++) {
  allDescendants(children[i]);
};

你知道你在这里嵌套了多少个数组吗? - thecoshman
只需使用m这个名称:m.parentNode.removeChild(m)。然而,可能会出现问题,因为在for循环中删除一个节点然后获取它的nextSibling将无法按预期工作。 - Dirk
@coshman,嵌套子元素的数量将是可变的。 - Matrym
@dirk,我没有想到那个。你有解决这个问题的建议吗? - Matrym
11个回答

58
function allDescendants (node) {
    for (var i = 0; i < node.childNodes.length; i++) {
      var child = node.childNodes[i];
      allDescendants(child);
      doSomethingToNode(child);
    }
}
你循环遍历所有的子元素,对于每个元素,你调用同一个函数并让它遍历该元素的子元素。

抱歉,您能否更明确地说明如何在我的情况下应用此函数? - Matrym
我认为这个更现代化的版本应该是 function allDescendants (node) { node.childNodes.forEach(child => { allDescendants(child); doSomethingToNode(child); }); } - bobajeff

50

通常你会有一个可以在所有节点上递归调用的函数。这实际上取决于您想对子节点做什么。如果您只想收集所有后代,则element.getElementsByTagName可能是更好的选择。

var all = node.getElementsByTagName('*');

for (var i = -1, l = all.length; ++i < l;) {
    removeTest(all[i]);
}

1
这将仅获取元素,而不是所有节点。 - Quentin
3
它们经过hasClass方法的测试,因此我相信它们打算将其作为元素处理。 - wombleton

4

不需要对所有子元素调用'allDescendants'方法,因为该方法本身已经执行了这个操作。因此,请删除最后一个代码块,我认为这是一个正确的解决方案(á,而不是thé =])

            function removeTest(child){     
                if(hasClass(child, "lbExclude")){
                    child.parentNode.removeChild(child);
                }
            }

            function allDescendants (node) {
                for (var i = 0; i < node.childNodes.length; i++) {
                  var child = node.childNodes[i];
                  allDescendants(child);
                  removeTest(child);
                }
            }           

            var children = allDescendants(temp);

我的'childNodes'丢失了。非常感谢! - Andre Carneiro

3
你可以使用广度优先搜索(BFS)来查找所有元素。
function(element) {
    // [].slice.call() - HTMLCollection to Array
    var children = [].slice.call(element.children), found = 0;
    while (children.length > found) {
        children = children.concat([].slice.call(children[found].children));
        found++;
    }
    return children;
};

该函数返回元素的所有子元素的子元素。

2
在现代浏览器或使用babel的情况下,最明确的方法是这样做。假设您有一个HTML节点$node,您想要对其子节点进行递归处理。
Array.prototype.forEach.call($node.querySelectorAll("*"), function(node) {
  doSomethingWith(node);
});

在任何DOM节点上使用querySelectorAll('*')将会给你返回该元素的所有子节点,它们将以一个NodeList形式呈现。 由于NodeList是类似数组的对象,因此你可以使用Array.prototype.forEach.call来迭代这个列表,在回调函数中逐一处理每个子节点。

1
非常抱歉我的无知!但是,'$node'需要类似于JQuery的东西吗?这个解决方案对于“纯净”的JavaScript代码有效吗? - Andre Carneiro
1
不,$node只是一个保存HTMLNode的变量名 - 不要被$符号搞混了 - 任何变量都可以有$。 - kumarharsh

2

要将所有后代作为数组获取,请使用以下代码:

function getAllDescendants(node) {
    var all = [];
    getDescendants(node);

    function getDescendants(node) {
        for (var i = 0; i < node.childNodes.length; i++) {
            var child = node.childNodes[i];
            getDescendants(child);
            all.push(child);
        }
    }
    return all;
}

1
如果您使用jquery并且想获取所有后代元素,可以使用以下代码:
 var all_children= $(parent_element).find('*');

请注意,all_children 是一个 HTML 集合而不是数组。当您仅循环时,它们的行为类似,但集合没有许多有用的 Array.prototype 方法,否则您可能会享受到这些方法。


1
如果在循环中创建项目,应该通过id =“” data-name或某些其他方式留下索引。然后可以直接对它们进行索引,这对于大多数函数(例如!-F)来说会更快。根据您的操作,对于1024位x 100个项目效果非常好。
if ( document.getElementById( cid ) ) {
 return;
} else {
  what you actually want
}

在大多数情况下,一旦项目已经被加载,使用此方法会更快。只有在重新加载页面或进行安全域传输/登录/CORS等操作时才需要刷新页面,否则您会重复某些操作。

0
TreeNode node = tv.SelectedNode;
while (node.Parent != null)
{
    node = node.Parent;
}                    
CallRecursive(node);


private void CallRecursive(TreeNode treeNode)
{            
    foreach (TreeNode tn in treeNode.Nodes)
    {
        //Write whatever code here this function recursively loops through all nodes                 
        CallRecursive(tn);
    }
}

0

如果您使用JS库,那么这非常简单:

$('.lbExclude').remove();

否则,如果您想获取节点下的所有元素,可以本地收集它们:
var nodes = node.getElementsByTagName('*');
for (var i = 0; i < nodes.length; i++) {
  var n = nodes[i];
  if (hasClass(n, 'lbExclude')) {
    node.parentNode.removeChild(node);
  }
}

糟糕,我没有看到@J-P的答案。 - wombleton

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接