2

如果我有一组元素:

<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>

在事先不知道元素结构具体是什么的情况下,检索嵌套最多的子元素(在本例中为跨度“Text 1”和“Text 3”)的最佳方法是什么(使用 jQuery)?

这是我正在使用的jsFiddle 。

另外,如果以前有人问过这个问题,我深表歉意,但我找不到类似这个问题的具体内容。

4

5 回答 5

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())
    );
});
于 2013-10-08T22:37:44.880 回答
2

您需要使用:last过滤器

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

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

于 2013-10-08T22:41:52.653 回答
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 为“#aaa”的最内层。它会删除 id "#zzz"。如果还想选择 id "#zzz",则必须修改开头的代码以从 "all_parent_elements" 中删除直接文本也与搜索文本匹配的元素。

于 2015-10-14T14:53:13.517 回答
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);
});

小提琴

于 2013-10-08T22:33:05.937 回答
-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>
于 2013-10-08T22:06:19.677 回答