查找没有特定祖先的后代元素

Find descendant elements that do not have a specific ancestor

我希望能够 select 一个元素并找到具有特定 class 但不包含在相似父元素中的所有后代元素。很难描述:

Html:

<div class="js-test js-1">
    <div class="b">1</div>
    <div class="b">1</div>
    <div class="d">
        <div class="b">1</div>        
    </div>
    <div class="js-test js-2">
        <div class="b">2</div>
        <div class="b">2</div>
        <div class="b">2</div>
        <div class="d">
            <div class="b">2</div>        
        </div>
        <div class="js-test js-3">
            <div class="b">3</div>
            <div class="b">3</div>
            <div class="b">3</div>
            <div class="b">3</div>
            <div class="d">
                <div class="b">3</div>        
            </div>
        </div>
    </div>
</div>

已尝试 jQuery:

$(document).ready(function(){
    function test(element)
    {
        var test2 = element.find('.b :not(.js-test .b)');
        console.log(test2.length);
    }
    
    console.clear();
    test($('.js-1'));
    test($('.js-2'));
    test($('.js-3'));
});

预期结果:

3

4

5

实际结果:

0

0

0

JsFiddle Example

您必须进行一些过滤以仅计算 .b 的出现次数,其中最接近的 .js-test 等于 element:

element.find('.b').filter(function() {
    return $(this).closest('.js-test').is(element);
}).length;

Here's a fiddle

尝试

// descendant `.b` of `element`,
// descendant `.b` of `element`, not `.b`, not `.js-test`
var test2 = element.find("> .b, > :not(.b):not(.js-test) .b");

jsfiddle http://jsfiddle.net/ku2pdn2j/4/


    $(document).ready(function(){
        function test(element) {
            var test2 = element.find("> .b, > :not(.b):not(.js-test) .b");
            console.log(test2.length, test2);
        }
        
        console.clear();
        test($('.js-1'));
        test($('.js-2'));
        test($('.js-3'));
    });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
   <div class="js-test js-1">
        <div class="b">1</div>
        <div class="b">1</div>
        <div class="d">
            <div class="b">1</div>        
        </div>
        <div class="js-test js-2">
            <div class="b">2</div>
            <div class="b">2</div>
            <div class="b">2</div>
            <div class="d">
                <div class="b">2</div>        
            </div>
            <div class="js-test js-3">
                <div class="b">3</div>
                <div class="b">3</div>
                <div class="b">3</div>
                <div class="b">3</div>
                <div class="d">
                    <div class="b">3</div>        
                </div>
            </div>
        </div>
    </div>

选择器 .b :not(.js-test .b) 查找 .b 元素的后代,这些元素不是 .js-test .b 元素。这个选择器的问题是双重的:

  • 每个 .b 元素都是 .js-test 元素的后代。这包括直接嵌套在您正在测试的每个上下文 .js-test 元素 中的 .b 元素

  • 第一个.b和第一个:not()之间的space表示后代选择器,也就是:not()表示的元素很可能 :not(.b) 完全匹配并且仍然匹配。

    但是您的 .b 个元素中的 none 个元素有任何元素后代,这就是您所有测试结果为零的真正原因。

由于不能直接创建context元素对应的选择器(参数element),需要像billyonecan提出的那样写一个自定义的过滤函数,根据是否过滤它最近的 .js-test 祖先是上下文元素。

我最终使用了类似于 的答案:

$(document).ready(function(){
    function test(element)
    {
        var all = element.find('.b');
        var exclude = element.find('.js-test .b');
        var test = all.not(exclude);
        console.log(test.length);
    }
    
    console.clear();
    test($('.js-1'));
    test($('.js-2'));
    test($('.js-3'));
});

实际结果:

3

4

5

预期应用程序的结果集非常小,我认为这里的任何解决方案在性能上都没有显着差异。