使用 jQuery 和 CSS 选择器选择嵌套元素的共同父/祖先
Posted
技术标签:
【中文标题】使用 jQuery 和 CSS 选择器选择嵌套元素的共同父/祖先【英文标题】:Select common parent/ancestor of nested elements with jQuery and CSS Selector 【发布时间】:2015-02-27 21:10:40 【问题描述】:我希望选择多个嵌套元素的公共父级,我只知道其内部文本。
例如在下面的代码中:
<unknown>
<unknown class="unknown">
....
<unknown>
<unknown>Sometext</unknown>
</unknown>
<unknown>
<unknown>Sometext</unknown>
</unknown>
<unknown>
<unknown>Sometext</unknown>
</unknown>
....
</unknown>
</unknown>
我想获取在这种情况下类未知的最近元素(公共父级)。我不知道实际的标签或类名。我只知道嵌套元素包含“Sometext”。我知道这可以通过使用 jQuery/javascript 的循环来完成,但是是否有一个 CSS 选择器可以与 jQuery 一起使用来找到它?我尝试使用最接近(),父母(),父母Until()的组合,但我似乎无法到达这个元素。
谢谢!
【问题讨论】:
所以你的意思是,如果第一个“Sometext”的直接父级是class="unknown"
,它会忽略这一点并仍然选择***的,因为这对所有“Sometext”都是通用的?
是的,没错。
【参考方案1】:
首先,你需要确保你只匹配叶子节点(没有子节点的节点),所以使用:
: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 的建议,这里是一对 jQuery 扩展(commonParents()
和 commonParent()
),将来可能会被人们使用:
要查找 jQuery 集合的所有共同父项,请使用 `commonParents()':
$.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()
在commonParent
中与commonParents
filter()
的组合使用,它只调用commonParents
中的代码直到第一次匹配,所以@ 987654339@ 不需要提高效率。
【讨论】:
干得好,这是用插件形式重写的方法的一个版本:JS Fiddle demo。 @David Thomas:很好地包装为扩展。我不认为这是经常需要的,以使其成为扩展,但我会在答案中添加我自己的扩展。 是的,我想它可能是相对不经常出现的问题之一,但我看到了你的答案,并有一些时间......现在,如果你可以工作,可能会搜索-在您的答案中加上长尾应该令人印象深刻。 :) 真棒回答 TrueBlueAusie。感谢您详细解释该过程。【参考方案2】:这应该可以完成工作。您基本上找到所有匹配元素的所有相关父级,获取每个集合的交集,然后抓取第一个以获取嵌套最多的公共父级。
您甚至可以将其封装为 jquery 插件。
if(console && console.clear) console.clear();
// create a handy intersection method for Arrays
// see http://***.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>
【讨论】:
感谢 Rhumborl。如果我真的知道父母的班级,这将起作用。但是,我命名为未知,因为它会有所不同。这是我想出的以获得我需要的东西,但我认为它可以改进/重构:var jq = $('*').find(':last:contains("Sometext")'); var prnt = $(jq[0]); jq.each(function () prnt = prnt.parents().add(prnt).has(this).last(); ); return prnt;
哦,对了,所以类位实际上是无关紧要的?如果你只想要 共同的父级,只需将 parentClass 设置为 *
。以上是关于使用 jQuery 和 CSS 选择器选择嵌套元素的共同父/祖先的主要内容,如果未能解决你的问题,请参考以下文章