jQuery - 查找所有后代元素,但不包括这些后代元素的后代元素

3

问题:

我试图使用JQuery的.find()在一个元素中找到所有后代,这些后代位于任何级别内,并具有给定属性,但不包含那些带有相同属性的子孙后代。

为了帮助理解:

JQuery

下面的查询旨在查找元素$("#some_id")内(在任何级别),具有some_attribute属性的所有后代,但不包括那些带有相同属性的子孙后代。

$("#some_id").find("[some_attribute]");

HTML

<span id="some_id" some_attribute>
    <span some_attribute> <!-- SELECT -->
        <span some_attribute> <!-- IGNORE -->
            <span some_attribute> <!-- IGNORE -->
            </span>
        </span>
        <span>
        </span>
    </span>
    <span>
        <span some_attribute> <!-- SELECT -->
            <span>
                <span some_attribute> <!-- IGNORE -->
                </span>
            </span>
            <span some_attribute> <!-- IGNORE -->
            </span>
        </span>
    </span>
    <span>
        <span>
            <span>
                <span some_attribute> <!-- SELECT -->
                </span>
            </span>
        </span>
    </span>
</span>

注意:我需要一个通用的方法......让我更好地解释一下!假设我不知道选择器$("#some_id"),我只有这个查询的结果。还要考虑到这个结果可能是指可能位于其他带有some_attribute属性的元素内部的元素。


1
你想要拥有一个带有属性的后代,只要它们不是具有相同属性的其他元素的(间接)后代? - Taplar
@Taplar 是的!完全正确!=D - Eduardo Lucio
2个回答

3

您可以使用:not来确保所选元素不匹配特定选择器 - 在这里,#some_id [some_attribute] [some_attribute](因为与该选择器匹配的元素将会是一个嵌套在另一个不是#some_idsome_attribute中的some_attribute):

const result = $("#some_id")
  .find("[some_attribute]:not(#some_id [some_attribute] [some_attribute])")
  .each(function() {
    console.log(this.innerHTML);
  });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<span id="some_id" some_attribute>
    <span some_attribute>sel <!-- SELECT -->
        <span some_attribute> <!-- IGNORE -->
            <span some_attribute> <!-- IGNORE -->
            </span>
        </span>
        <span>
        </span>
    </span>
    <span>
        <span some_attribute>sel <!-- SELECT -->
            <span>
                <span some_attribute> <!-- IGNORE -->
                </span>
            </span>
            <span some_attribute> <!-- IGNORE -->
            </span>
        </span>
    </span>
    <span>
        <span>
            <span>
                <span some_attribute>sel <!-- SELECT -->
                </span>
            </span>
        </span>
    </span>
</span>

如果您不能进行硬编码,我想一种选择是设置属性,以便您可以正确地使用 :not

const elm = $("#some_id");
elm[0].dataset.parent = '';
elm
  .find("[some_attribute]:not([data-parent] [some_attribute] [some_attribute])")
  .each(function() {
    console.log(this.innerHTML);
  });
elm[0].removeAttribute('data-parent');
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<span id="some_id" some_attribute>
    <span some_attribute>sel <!-- SELECT -->
        <span some_attribute> <!-- IGNORE -->
            <span some_attribute> <!-- IGNORE -->
            </span>
        </span>
        <span>
        </span>
    </span>
    <span>
        <span some_attribute>sel <!-- SELECT -->
            <span>
                <span some_attribute> <!-- IGNORE -->
                </span>
            </span>
            <span some_attribute> <!-- IGNORE -->
            </span>
        </span>
    </span>
    <span>
        <span>
            <span>
                <span some_attribute>sel <!-- SELECT -->
                </span>
            </span>
        </span>
    </span>
</span>

如果您不想更改 DOM,也可以使用 .filter 并检查具有 [some_attribute].closest 元素是否是父元素:

const elm = $("#some_id");
elm
  .find("[some_attribute]")
  .filter(function() {
    return $(this).parent().closest('[some_attribute]')[0] === elm[0];
  })
  .each(function() {
    console.log(this.innerHTML);
  });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<span id="some_id" some_attribute>
    <span some_attribute>sel <!-- SELECT -->
        <span some_attribute> <!-- IGNORE -->
            <span some_attribute> <!-- IGNORE -->
            </span>
        </span>
        <span>
        </span>
    </span>
    <span>
        <span some_attribute>sel <!-- SELECT -->
            <span>
                <span some_attribute> <!-- IGNORE -->
                </span>
            </span>
            <span some_attribute> <!-- IGNORE -->
            </span>
        </span>
    </span>
    <span>
        <span>
            <span>
                <span some_attribute>sel <!-- SELECT -->
                </span>
            </span>
        </span>
    </span>
</span>

使用旧版本的jQuery,你可以使用.selector

const elm = $("#some_id");
const sel = elm.selector;
elm
  .find(`[some_attribute]:not(${sel} [some_attribute] [some_attribute])`)
  .each(function() {
    console.log(this.innerHTML);
  });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.7/jquery.min.js"></script>
<span id="some_id" some_attribute>
    <span some_attribute>sel <!-- SELECT -->
        <span some_attribute> <!-- IGNORE -->
            <span some_attribute> <!-- IGNORE -->
            </span>
        </span>
        <span>
        </span>
    </span>
    <span>
        <span some_attribute>sel <!-- SELECT -->
            <span>
                <span some_attribute> <!-- IGNORE -->
                </span>
            </span>
            <span some_attribute> <!-- IGNORE -->
            </span>
        </span>
    </span>
    <span>
        <span>
            <span>
                <span some_attribute>sel <!-- SELECT -->
                </span>
            </span>
        </span>
    </span>
</span>


我需要一个更通用的方法。我来解释一下,假设我不知道选择器 $("#some_id"),我只有该查询的结果。同时考虑到这个结果可能指向一个带有 some_attribute 属性的另一个元素内部。谢谢!=D - Eduardo Lucio
也许有一些方法可以防止 .find() 在已经搜索过的元素中再次搜索。 =D - Eduardo Lucio
这里 https://stackoverflow.com/q/38352374/3223785 有一个非常相似的问题。 OP在这里 https://jsfiddle.net/netaques/sc72fq1x/ 给出了一个答案。但是,它似乎不是一个好的解决方案... =/ - Eduardo Lucio
1
你可以在旧版本的jQuery中使用.selector,但它已经不再被支持了(自1.9版起)。 - CertainPerformance
我正在测试并尝试理解为什么在我的实际情况中它不起作用。我会给你反馈!=D - Eduardo Lucio
我测试了解决方案"If you don't want to change the DOM either [...]",但出于某些原因,在我的"真实代码"中它对我不起作用。我在这个线程上发布了一个对我有效的解决方案(function findDescsNotDescsOfThose(jqPntElOrPntQry, jqFind))。谢谢!=D - Eduardo Lucio

0
这是我的解决方案。更多的解释请参见下面的代码注释...
// NOTE: Find all descendants at any level, but not the descendants of those descendants.
// By Questor
function findDescsNotDescsOfThose(jqPntElOrPntQry, jqFind){
    var jqElInst;
    if (typeof jqPntElOrPntQry === "string" || 
            jqPntElOrPntQry instanceof String) {
    // [Ref.: https://dev59.com/HW855IYBdhLWcg3w-JQr#9436948 ]

        jqElInst = $(jqPntElOrPntQry);
    } else {
        jqElInst = jqPntElOrPntQry;
    }
    return jqElInst.find(jqFind)
        .filter(function(){

            // NOTE: We need use ".parent ()" and then ".closest ()", otherwise ".closest ()"
            // will find the element itself if it fits "jqFind". By Questor
            descOfjqFind = $(this).parent().closest(jqFind);

            // NOTE: Checks if it is not descended from any element that also fits
            // in "jqFind". Being descended from an element that also fits "jqFind"
            // checks to see if this element is descended from "jqElInst". By Questor
            if (descOfjqFind.length > 0 && $(descOfjqFind).
                    parent().closest(jqElInst).length === 1) {
                return false
            }

            return true;
    });
}

谢谢!=D


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