是否存在类似于jQuery
.closest()
的函数,但是为了遍历后代并仅返回最接近的后代?
我知道有.find()
函数,但它返回所有可能的匹配,而不是最接近的。
修改
这是最近的的定义(至少对我而言):
首先,遍历所有儿童,然后遍历每个儿童。
在下面给出的示例中,id='2'
是.closest
的最近id="find-my-closest-descendant"
个后代
<div id="find-my-closest-descendant">
<div>
<div class="closest" Id='1'></div>
</div>
<div class="closest" Id='2'></div>
</div>
请参阅JSfiddle link。
答案 0 :(得分:105)
如果“最接近”的后代是指第一个孩子,那么你可以这样做:
$('#foo').find(':first');
或者:
$('#foo').children().first();
或者,要查找特定元素的第一个匹配项,您可以执行以下操作:
$('#foo').find('.whatever').first();
或者:
$('#foo').find('.whatever:first');
但实际上,我们需要对“最接近的后代”的含义有一个明确的定义。
E.g。
<div id="foo">
<p>
<span></span>
</p>
<span></span>
</div>
哪<span>
会$('#foo').closestDescendent('span')
返回?
答案 1 :(得分:42)
根据您对closest
的定义,我编写了以下插件:
(function($) {
$.fn.closest_descendent = function(filter) {
var $found = $(),
$currentSet = this; // Current place
while ($currentSet.length) {
$found = $currentSet.filter(filter);
if ($found.length) break; // At least one match: break loop
// Get all children of the current set
$currentSet = $currentSet.children();
}
return $found.first(); // Return first match of the collection
}
})(jQuery);
答案 2 :(得分:16)
您可以将find
与:first
选择器一起使用:
$('#parent').find('p:first');
以上行会在<p>
的后代中找到第一个#parent
元素。
答案 3 :(得分:2)
这种做法怎么样?
$('find-my-closest-descendant').find('> div');
这个“直接孩子”选择器适合我。
答案 4 :(得分:1)
纯JS解决方案(使用ES6)。
export function closestDescendant(root, selector) {
const elements = [root];
let e;
do { e = elements.shift(); } while (!e.matches(selector) && elements.push(...e.children));
return e.matches(selector) ? e : null;
}
考虑以下结构:
div == $0 ├── div == $1 │ ├── div │ ├── div.findme == $4 │ ├── div │ └── div ├── div.findme == $2 │ ├── div │ └── div └── div == $3 ├── div ├── div └── div
closestDescendant($0, '.findme') === $2;
closestDescendant($1, '.findme') === $4;
closestDescendant($2, '.findme') === $2;
closestDescendant($3, '.findme') === null;
function closestDescendant(root, selector) {
const elements = [root];
let e;
do { e = elements.shift(); } while (!e.matches(selector) && elements.push(...e.children));
return e.matches(selector) ? e : null;
}
const [$0, $1, $2, $3, $4] = [0, 1, 2, 3, 4].map(x => document.querySelector(`#e${x}`));
console.log(closestDescendant($0, '.findme')); // $2
console.log(closestDescendant($1, '.findme')); // $4
console.log(closestDescendant($2, '.findme')); // $2
console.log(closestDescendant($3, '.findme')); // null
<div id="e0">
<div id="e1">
<div></div>
<div id="e4" class="findme"></div>
<div></div>
<div></div>
</div>
<div id="e2" class="findme">
<div></div>
<div></div>
</div>
<div id="e3">
<div></div>
<div></div>
<div></div>
</div>
</div>
答案 5 :(得分:1)
如果有人正在寻找纯JS解决方案(使用ES6而不是jQuery),这是我使用的一个解决方案:
'by_reference' => false,
答案 6 :(得分:0)
我认为首先你必须定义“最接近”的含义。如果您的意思是符合您的条件的子节点,就父母链接而言是最短的距离,那么使用“:first”或“.eq(0)”将不一定有效:
<div id='start'>
<div>
<div>
<span class='target'></span>
</div>
</div>
<div>
<span class='target'></span>
</div>
</div>
在该示例中,第二个“.target”<span>
元素“更接近”“开始”<div>
,因为它只有一个父母一跳。如果这就是“最接近”的意思,则需要在过滤函数中找到最小距离。 jQuery选择器的结果列表始终采用DOM顺序。
也许:
$.fn.closestDescendant = function(sel) {
var rv = $();
this.each(function() {
var base = this, $base = $(base), $found = $base.find(sel);
var dist = null, closest = null;
$found.each(function() {
var $parents = $(this).parents();
for (var i = 0; i < $parents.length; ++i)
if ($parents.get(i) === base) break;
if (dist === null || i < dist) {
dist = i;
closest = this;
}
});
rv.add(closest);
});
return rv;
};
这是一个黑客插件,因为它构建结果对象的方式,但想法是你必须找到你找到的所有匹配元素中最短的父路径。由于<
检查,此代码偏向于DOM树中向左的元素; <=
会偏向正确。
答案 7 :(得分:0)
我做了这个,没有针对位置选择器的实现(他们需要的不仅仅是matchesSelector
):
演示:http://jsfiddle.net/TL4Bq/3/
(function ($) {
var matchesSelector = jQuery.find.matchesSelector;
$.fn.closestDescendant = function (selector) {
var queue, open, cur, ret = [];
this.each(function () {
queue = [this];
open = [];
while (queue.length) {
cur = queue.shift();
if (!cur || cur.nodeType !== 1) {
continue;
}
if (matchesSelector(cur, selector)) {
ret.push(cur);
return;
}
open.unshift.apply(open, $(cur).children().toArray());
if (!queue.length) {
queue.unshift.apply(queue, open);
open = [];
}
}
});
ret = ret.length > 1 ? jQuery.unique(ret) : ret;
return this.pushStack(ret, "closestDescendant", selector);
};
})(jQuery);
可能存在一些错误,但没有对它进行过多次测试。
答案 8 :(得分:0)
//closest_descendent plugin
$.fn.closest_descendent = function(filter) {
var found = [];
//go through every matched element that is a child of the target element
$(this).find(filter).each(function(){
//when a match is found, add it to the list
found.push($(this));
});
return found[0]; // Return first match in the list
}
答案 9 :(得分:0)
如果匹配选择器,我会使用以下内容来包含目标:
var jTarget = $("#doo");
var sel = '.pou';
var jDom = jTarget.find(sel).addBack(sel).first();
标记:
<div id="doo" class="pou">
poo
<div class="foo">foo</div>
<div class="pou">pooo</div>
</div>
答案 10 :(得分:0)
尽管这是一个古老的话题,但我无法抗拒实施我最近的孩子。 提供第一个发现最少旅行的后代(先呼吸)。 一个是递归的(个人喜欢的),另一个是使用todo列表,所以没有递归作为jQquery扩展。
希望有人受益。
注意:递归获取堆栈溢出,并且我改进了另一个,现在与之前给出的答案类似。
jQuery.fn.extend( {
closestChild_err : function( selector ) { // recursive, stack overflow when not found
var found = this.children( selector ).first();
if ( found.length == 0 ) {
found = this.children().closestChild( selector ).first(); // check all children
}
return found;
},
closestChild : function( selector ) {
var todo = this.children(); // start whith children, excluding this
while ( todo.length > 0 ) {
var found = todo.filter( selector );
if ( found.length > 0 ) { // found closest: happy
return found.first();
} else {
todo = todo.children();
}
}
return $();
},
});
答案 11 :(得分:0)
以下插件返回第n个最接近的后代。
$.fn.getNthClosestDescendants = function(n, type) {
var closestMatches = [];
var children = this.children();
recursiveMatch(children);
function recursiveMatch(children) {
var matches = children.filter(type);
if (
matches.length &&
closestMatches.length < n
) {
var neededMatches = n - closestMatches.length;
var matchesToAdd = matches.slice(0, neededMatches);
matchesToAdd.each(function() {
closestMatches.push(this);
});
}
if (closestMatches.length < n) {
var newChildren = children.children();
recursiveMatch(newChildren);
}
}
return closestMatches;
};
答案 12 :(得分:0)
我正在寻找一个类似的解决方案(我想要所有最接近的后代,即广度优先+所有匹配,无论它存在哪个级别),这是我最终做的事情:
var item = $('#find-my-closest-descendant');
item.find(".matching-descendant").filter(function () {
var $this = $(this);
return $this.parent().closest("#find-my-closest-descendant").is(item);
}).each(function () {
// Do what you want here
});
我希望这会有所帮助。
答案 13 :(得分:0)
您可以简单地输入
$("#find-my-closest-descendant").siblings('.closest:first');
答案 14 :(得分:0)
有一篇很棒的文章指出,最接近的[Geeks for Geeks]可以轻松实现OP的要求。
1 https://www.geeksforgeeks.org/jquery-closest-with-examples/
答案 15 :(得分:-2)
你有很多选择,但$("#parent").children(".child");
是最快的。
check this article for details and benchmark