【问题标题】:Finding all "X-generation" descendants using jQuery使用 jQuery 查找所有“X 代”后代
【发布时间】:2011-09-17 05:59:26
【问题描述】:

已解决(某种

好吧,我想我使用以下方法解决了它(排除边缘情况):

function findByDepth(parent, child, depth){
    var children = $();
    $(child, $(parent)).each(function(){
        if($(this).parentsUntil(parent, child).length == (depth - 1)){
            children = $(children).add($(this));
        }
    });
    return children;
}

// this would successfully return the 3.X elements of an HTML snippet structured
// as my XML example, where <parent> = #parent, etc.
var threeDeep = findByDepth('#parent', '.child', 3);

但是有人必须在这里得到公认的答案,我不会自己回答这个问题,也不会带着你来之不易的代表潜逃。因此,如果有人想添加任何内容,例如提供有关优化此功能的见解(在我去之前,$.extend() 它在)我可能会将您的答案标记为正确,否则会退回标记任何人首先是我最初的问题。

顺便检查一下fiddle:http://jsfiddle.net/5PDaA/

子更新

再次查看@CAFxX 的答案,我意识到他的方法可能更快,在可以的浏览器中利用querySelectorAll。无论如何,我将他的方法修改为以下内容,但它仍然让我大笑:

$.fn.extend({
    'findAtDepth': function(selector, depth){
        var depth = parseInt(depth) || 1;
        var query = selector;
        for(var i = 1; i < depth; i++){
            query += (' ' + selector);
        }
        return $(query, $(this)).not(query + ' ' + selector);
    }
});

它第一次运行良好,但是当上下文更改为在 selector 中找到的元素时,由于某种原因它失败了。


更新

好吧,我愚蠢地不清楚,也不知道我在做什么的规格。由于我已经审查了我的实施,我将在这里更新;我会标记满足我最初要求的最早答案,因为人们认为我如此无偿更新是个傻瓜(我不会怪你)但是我在下面提到的奖励是本质上是一个要求。我会发布另一个问题,但它可能会因重复而关闭。无论如何,只要您耐心等待,+1 就在您身边:

深度规范给定的孩子是必要的(考虑到它被包裹在一个函数中或以其他方式)因此隔离一个孩子并且同样嵌套(不一定是兄弟姐妹) 匹配元素。

例如(XML 为简洁):

<!-- depth . sibling-index-with-respect-to-depth -->

<parent>
    <child>                     <!-- 1.1 -->
        <child>                 <!-- 2.1 -->
            <child>             <!-- 3.1 -->
                <child></child> <!-- 4.1 -->
            </child>            
            <child>             <!-- 3.2 -->
                <child></child> <!-- 4.2 -->
            </child>            
        </child>                
        <child>                 <!-- 2.2 -->
            <child></child>     <!-- 3.3 -->
        </child>                
    </child>                    
</parent>

给定一个指定的深度2,所有2.X 元素都会被选中。给定4 所有4.X,以此类推。


原始问题

使用 jQuery 的原生功能,有没有办法只选择与选择器匹配的“第一代”后代?例如:

注意:以下仅为示例。 .child 元素嵌套在任意级别的父级中。

奖励:正如我在下面提出的语法所示,提供一种方法来指定选择应遍历的深度的答案将是难以置信

// HTML
<div id="parent">
    <div>
        <div class="child"> <!-- match -->
            <div>
                <div class="child"> <!-- NO match -->
                </div>
            </div>
        </div>
        <div class="child"> <!-- match -->
            <div>
                <div class="child"> <!-- NO match -->
                </div>
            </div>
        </div>
    </div>
</div>

还有:

// jQuery
$('#parent').find('.child:generation(1)'); // something in that vein

尝试从#parent 的上下文中进行选择,jQuery :first 在这里不起作用,因为它只命中第一个匹配的.child

【问题讨论】:

  • 孩子的深度是任意的,还是总是在一个div中? #parent&gt;div&gt;.child 将适用于此示例
  • 感谢@Andy Ray - 刚刚更新以反映;是的,任意深度。可能是直系子女,可能有好几个层次。

标签: jquery children descendant


【解决方案1】:

试试这个(亲吻!):

$("#parent .child").not(".child .child");

编辑:获得第二级:

$("#parent .child .child").not(".child .child .child");

第三个:

$("#parent .child .child .child").not(".child .child .child .child");

等等......所以你可以(未经测试):

function findChildrenDeepDown(parentSelector, level) {
  level = parseInt(level);
  var firstSelctor = parent, notSelector = ".child", i;
  for (i=0; i<level; i++) {
    firstSelector += " .child";
    notSelector += " .child";
  }
  return $(firstSelector).not(notSelector);
}

findChildrenDeepDown("#parent", 3); // find third-level children of #parent

【讨论】:

  • 感谢@CAFxX - 这似乎完成了这项工作。关于我上面更新的 bonus 有什么建议吗?也许使用.not():not() 方法进行某种迭代?
  • 你去吧,不是很优雅,但它应该可以工作。您可以将其包装在一个函数中,该函数将" .child" 连接 N 次(N 为所需的深度),然后调用 $()
  • 你知道,这可能是计算成本最低的方法。双向遍历树,遍历元素以隔离给定深度可能会很昂贵,但这不应该。
  • 还有一种更优雅的方式:$("#parent").find(".child").siblings();(如我的帖子中所说)
  • 嗯,似乎不起作用; .not() 子句干扰了大于 1 的深度规范。
【解决方案2】:

一般来说,我认为您必须找到所有 .child 元素,然后丢弃那些具有 .child 祖先的元素:

$('#parent .child').filter(function() {
    return $(this).parent().closest('.child').length == 0;
});

不过,这并不能处理这样的事情:

<div id="parent">
    <div class="child"> <!-- match -->
        <div>
            <div class="child"> <!-- NO match -->
            </div>
        </div>
    </div>
    <div>
        <div>
            <div class="child"> <!-- NO match wanted but it will match -->
            </div>
        </div>
    </div>
</div>

但也许它足以满足您的 HTML 结构。

【讨论】:

  • 谢谢@mu - 这是一个好的方向; CAFxX 的响应解决了最初的问题,当然也支持 KISS,但是根据我的 bonus 更新要求,程序化方法将提供更大的灵活性。
  • Big ole' 一堆嵌套元素,但正如我的 bonus 提到的(在我考虑实现时,这确实是一个要求)指定相对于选择器(.child 或其他)的深度的能力会很棒。我知道你要去哪里;可能是$('.child:first').siblings('.child'),但深度规范会很棒。
  • @Bracketworks:您可以跳过 jQuery 并通过 DOM 执行 BFS 以找到您的起始 .child,然后横向移动以获取该深度的其余部分;然后将它们与x=$();x.add() 一起堆放;可能不漂亮,但它应该工作。顺便说一句,回答你自己的问题很好,接受你自己的回答也很好(甚至有一个badge 用于那种事情)。
【解决方案3】:

你可以这样得到它:

$("#parent").find(">div>.child")

编辑

如果第一个孩子可以在随机深度,你可以使用

$("#parent").find(".child").siblings();

【讨论】:

  • 谢谢@Arnaud F. - 根据安迪的评论,我更新了问题; .child 元素可以相对于#parent 存在任意深度。另外,对于-1'er;可能没有保证,他的回答是更新前的。
  • 这只有在保证有两个顶层子节点可以找到并且没有任何底层子节点彼此相邻的情况下才有效
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-16
  • 2011-02-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多