使用jQuery有没有办法找到最远(最深,或最嵌套)的子元素?

时间:2013-10-08 21:44:50

标签: jquery

如果我有一组元素:

<div class="start">
    <div>
        <span>Text 1</span>
    </div>
</div>

<div class="start">
    <span>
        <div>
            <span>Text 2</span>
        </div>
        <div>
            <div>
                <span>Text 3</span>
            </div>
        </div>
    </span>
</div>

最好的方法(使用jQuery)检索最嵌套的子元素(在这种情况下是跨越“Text 1”和“Text 3”),而不知道具体事先是什么元素结构?

这是我正在使用的jsFiddle

另外,如果之前有人问我,我很抱歉,但我没有找到类似这个问题的任何内容。

5 个答案:

答案 0 :(得分:4)

这是一个实现,它使用我之前编写的treeWalk函数,然后将其包装在jquery方法中,该方法查找传入的jQuery对象中每个项目的最深层后代,并返回包含这些节点的新jQuery对象。

使用递归和大量jQuery的解决方案可以使用更少的代码来完成,但它可能会更慢。这是基于遍历树的通用本机JS树步行函数。

使用比OP的HTML更复杂的HTML测试用例的演示:http://jsfiddle.net/jfriend00/8tC3a/

$.fn.findDeepest = function() {
    var results = [];
    this.each(function() {
        var deepLevel = 0;
        var deepNode = this;
        treeWalkFast(this, function(node, level) {
            if (level > deepLevel) {
                deepLevel = level;
                deepNode = node;
            }
        });
        results.push(deepNode);
    });
    return this.pushStack(results);
};

var treeWalkFast = (function() {
    // create closure for constants
    var skipTags = {"SCRIPT": true, "IFRAME": true, "OBJECT": true, "EMBED": true};
    return function(parent, fn, allNodes) {
        var node = parent.firstChild, nextNode;
        var level = 1;
        while (node && node != parent) {
            if (allNodes || node.nodeType === 1) {
                if (fn(node, level) === false) {
                    return(false);
                }
            }
            // if it's an element &&
            //    has children &&
            //    has a tagname && is not in the skipTags list
            //  then, we can enumerate children
            if (node.nodeType === 1 && node.firstChild && !(node.tagName && skipTags[node.tagName])) {                
                node = node.firstChild;
                ++level;
            } else if (node.nextSibling) {
                node = node.nextSibling;
            } else {
                // no child and no nextsibling
                // find parent that has a nextSibling
                --level;
                while ((node = node.parentNode) != parent) {
                    if (node.nextSibling) {
                        node = node.nextSibling;
                        break;
                    }
                    --level;
                }
            }
        }
    }
})();

var deeps = $(".start").findDeepest();

deeps.each(function(i,v){
    $("#results").append(
        $("<li>").html($(v).prop("tagName") + " " + $(v).html())
    );
});

答案 1 :(得分:2)

您需要使用:last过滤器

$('.start').find(':last');

工作小提琴:http://jsfiddle.net/BmEzd/1/

答案 2 :(得分:2)

使用最少的代码行的另一种方法(可能不那么快)可以如下:

var all_matched_elements = $(":contains('" + text_to_search + "')");
var all_parent_elements = $(all_matched_elements).parents();
var all_deepest_matches = $(all_matched_elements).not(all_parent_elements);

如果您的文本位于具有其他子元素的元素内,则此方法特别有用:

<div class="start">
    <div>
        <div>Text 1<span>Alpha Beta Gamma</span></div>
    </div>
</div>

但是,上面的代码不适用于看起来如下的DOM:

<div class="start">
        <div>
            <div id="zzz">search-text
                <div id="aaa">search-text</div>
            </div>  
        </div>
 </div>

在上述情况下,它只会选择内部最多的id&#34; #aaa&#34;。它会丢弃id&#34;#zzz&#34;。如果有人想选择id&#34;#zzz&#34;然后必须修改开头的代码以从&#34; all_parent_elements&#34;中删除元素。其直接文本也与搜索文本匹配。

答案 3 :(得分:0)

我认为这对你有用。

var deepestLevel = 0;
var deepestLevelText = "";

function findDeepNested(element, currentLevel) {
    if ((element.children().length == 0) && (deepestLevel < currentLevel)) {
        // No children and current level is deeper than previous most nested level
        deepestLevelText="<li>" + element.text() + "</li>";
    }
    else { // there are children, keep diving
        element.children().each( function () {
            findDeepNested($(this), currentLevel + 1);
        });
    }
}

$(".start").each( function () {
    deepestLevel = 0;
    deepestLevelText = "";
    findDeepNested($(this), 0);
    $("#results").append(deepestLevelText);
});

Fiddle

答案 4 :(得分:-1)

<script type="text/javascript">
    function findFarthestNode(node)
    {
        if(node.parent().length && node.parent().prop("tagName") != "BODY")
            return findFarthestNode(node.parent());
        return node;
    }
    jQuery(document).ready(function() {
        node = jQuery("span");
        farthest = findFarthestNode(node);
        console.log(farthest);
    });
</script>