使用jQuery和CSS Selector选择嵌套元素的公共父/祖先

时间:2014-12-31 22:24:07

标签: javascript jquery html jquery-selectors dom-traversal

我希望选择多个嵌套元素的公共父级,我只知道内部文本。

例如,在以下代码中:

<unknown>       
    <unknown class="unknown">
        ....
        <unknown>
            <unknown>Sometext</unknown>
        </unknown>
        <unknown>
            <unknown>Sometext</unknown>
        </unknown>
        <unknown>
            <unknown>Sometext</unknown>
        </unknown>
        ....
    </unknown>
</unknown>

我想获得在这种情况下具有类未知的最接近的元素(普通父元素)。我不知道实际的标签或类名。我只知道nest元素包含“Sometext”。我知道这可以通过使用jQuery / Javascript的循环完成,但是有一个CSS选择器,我可以使用jQuery来找到它吗?我尝试使用nearest(),parents(),parentsUntil()的组合,但我似乎无法使用此元素。

谢谢!

2 个答案:

答案 0 :(得分:3)

首先,您需要确保只匹配叶节点(没有子节点的节点),因此请使用:

:not(:has(*))

因此,要找到所有完全匹配(只是叶节点),请使用:

var matches = $(':not(:has(*))').filter(function () {
    return $(this).text() == "Sometext";
});

或仅对所有元素使用组合过滤器(添加了0个孩子的检查):

var matches = $('*').filter(function () {
     return !$(this).children().length && $(this).text() == "Sometext";
});

注意: 我还没有测试过这两个选项中哪一个最快。

然后你需要找到包含所有匹配的第一个祖先(第一个匹配):

var commonparent = matches.first().parents().filter(function () {
    return $(this).find(matches).length == matches.length;
}).first();

JSFiddle: http://jsfiddle.net/TrueBlueAussie/v4gr1ykg/

基于David Thomas&#39;建议,这里它是一对jQuery扩展(commonParents()commonParent()),可能将来会用于人们:

要查找jQuery集合的所有常见父项,请使用`commonParents()&#39;:

$.fn.commonParents = function (){
    var cachedThis = this;
    return cachedThis.first().parents().filter(function () {
        return $(this).find(cachedThis).length === cachedThis.length;
    });
};

JSFiddle :( commonParents): http://jsfiddle.net/TrueBlueAussie/v4gr1ykg/3/

要查找jQuery集合中最接近的公共父级,请使用commonParent()

$.fn.commonParent = function (){
    return $(this).commonParents().first();
};

JSFiddle :( commonParent): http://jsfiddle.net/TrueBlueAussie/v4gr1ykg/2/

注意:

  • jQuery优化first() commonParentcommonParents filter()的合并使用,并且只调用commonParents 中的代码,直到进行了第一场比赛,因此commonParent不需要提高效率。

答案 1 :(得分:0)

这应该可以胜任。你基本上找到了所有匹配元素的所有相关父元素,得到每个集合的交集,然后抓住第一个集合来获得最嵌套的公共父元素。

您甚至可以像jquery插件一样将其打包。

if(console && console.clear) console.clear();

// create a handy intersection method for Arrays
// see http://stackoverflow.com/a/16227294/1901857
Array.prototype.intersect = function(arr) {
    var a = this, b = arr;
    var t;
    if (b.length > a.length) t = b, b = a, a = t; // indexOf to loop over shorter
    return a.filter(function (e) {
        return b.indexOf(e) > -1;
    });
};

;(function($) {
    $.fn.commonParents = function(selector) {
        // find all relevant parents for each element and get set intersection
        // pushStack means you can use end() etc in chaining correctly
        return this.pushStack(sometexts.get().reduce(function(prevParents, el) {
            // common parents for this element - note the lowest level parent is first
            var parents = $(el).parents(selector || '*').get();

            // intersect with the previous value (or itself if first)
            return (prevParents || parents).intersect(parents);
        }, null), "commonParents", arguments);
    };
})(jQuery);


// text to search for
var search = "Sometext";
// parent selector to filter parents by e.g. '.unknown' - use null for all parents
var parentSelector = null;

// find everything containing search
var sometexts = $(":contains('" + search + "')").filter(function() { return $(this).text() == search; });

// grab the first common parent - the lowest level one - or null if there isn't one
var commonParent = sometexts.commonParents(parentSelector).get(0);

console.log(commonParent);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div>
    <div class="unknown test">
        <div class="unknown test2">
            <div class="unknown">
                <div>Sometext</div>
            </div>
            <div>
                <div>Sometext</div>
            </div>
            <div>
                <div>Sometext</div>
            </div>
        </div>
    </div>
</div>