具有兄弟方法的伪选择器
早些时候,我回答了这个问题,基本上是关于删除表格行。这个问题是由于对该问题的评论而产生的。给定以下 HTML:
<div><a href="#" class="removelink">remove</a></div>
<table>
<tr>
<td>Row 1</td>
</tr>
</table>
和以下 jQuery:
$('.removelink').click(function(){
$(this).parent().siblings('table tr:last').remove();
});
我希望什么也不会发生,因为 siblings
方法应该选择当前匹配元素的同级元素,可以选择通过选择器进行过滤。来自 jQuery 文档:
该方法可以选择接受相同类型的选择器表达式 我们可以将其传递给 $() 函数。如果提供了选择器,则 元素将通过测试是否匹配来过滤。
基于此,我将上面的代码读为“获取当前元素(div
)的同级元素,它们是table
中的最后一个tr
>”。显然没有与该描述匹配的元素 - table
中有一个 tr
,但它不是 div
的同级元素。因此,我不希望返回任何元素。然而,它实际上返回整个表,就好像它完全忽略了选择器的 tr:last
部分一样。
让我更加困惑的是,如果删除 :last
伪选择器,它会按预期工作(不返回任何元素)。
为什么上面的代码删除了整个表?我只是愚蠢并且错过了一些明显的事情吗?您可以在此处查看上面的代码。
编辑 - 这是一个简化版本。给定以下 HTML:
<div id="d1"></div>
<div>
<span></span>
</div>
为什么以下 jQuery 返回第二个 div
:
$("#d1").siblings("div span:last");
我希望它不会返回任何内容,因为没有 span
是 的同级>#d1
。 这是这个简化示例的小提琴。
更新
根据@muistooshort的精彩调查,我创建了一个jQuery错误票< /a> 来跟踪这个问题。
Earlier, I answered this question, which was basically about removing a table row. This question came about as the result of the comments on that question. Given the following HTML:
<div><a href="#" class="removelink">remove</a></div>
<table>
<tr>
<td>Row 1</td>
</tr>
</table>
And the following jQuery:
$('.removelink').click(function(){
$(this).parent().siblings('table tr:last').remove();
});
I would expect nothing to happen, because the siblings
method should select the siblings of the currently matched element, optionally filtered by a selector. From the jQuery docs:
The method optionally accepts a selector expression of the same type
that we can pass to the $() function. If the selector is supplied, the
elements will be filtered by testing whether they match it.
Based on that, I read the above code as "get the siblings of the current element (the div
) which are the last tr
within a table
". Obviously there are no elements that match that description - there is a tr
within a table
, but it's not a sibling of the div
. So, I wouldn't expect any elements to be returned. However, it actually returns the entire table, as if it ignores the tr:last
part of the selector entirely.
What confused me further was that if you remove the :last
pseudo-selector, it works as expected (returning no elements).
Why is the entire table removed by the above code? Am I just being stupid and missing something obvious? You can see the above code in action here.
Edit - Here's a simplified version. Given the following HTML:
<div id="d1"></div>
<div>
<span></span>
</div>
Why does the following jQuery return the second div
:
$("#d1").siblings("div span:last");
I would expect it to return nothing, as there is not a span
which is a sibling of #d1
. Here's a fiddle for this simplified example.
Update
Following the brilliant investigation from @muistooshort, I have created a jQuery bug ticket to track this issue.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
请允许我稍微扩展一下我的评论。所有这些都基于您的第二个简化示例和 jQuery 1.6.4。这可能有点啰嗦,但我们需要浏览一下 jQuery 代码来了解它在做什么。
我们确实有可用的 jQuery 源代码,所以让我们去看看吧
穿过它,看看里面有什么奇迹。
siblings
的内部结构看起来像这样:包裹在这个:
然后
jQuery.sibling
是这样的:所以我们在 DOM 中向上一步,转到父级的第一个步骤孩子,
并继续横向获取所有父母的孩子(除了
我们开始的节点!)作为 DOM 元素的数组。
这样我们就可以得到
ret
中的所有同级 DOM 元素了现在来看看过滤:
那么
filter
到底是什么?filter
就是这样:在您的情况下,
elems
将只有一个元素(如#d1
有一个兄弟)所以我们开始使用
jQuery.find.matchesSelector
实际上是
Sizzle.matchesSelector
:一些实验表明 Gecko 和 WebKit 都没有
matchesSelector
的版本可以处理div span:first
所以我们结束在最后的
Sizzle()
调用中;请注意,Gecko 和 WebKitmatchesSelector
变体可以处理div span
和您的jsfiddles 在
div span
情况下按预期工作。Sizzle(expr, null, null, [node])
是做什么的?为什么它返回一个数组当然,您的
中包含
。我们会有
expr
中的 this:以及
node
中的 this:因此
位于
node
中> 与选择器完美匹配在
expr
中,并且Sizzle()
调用返回一个包含并且由于该数组具有非零长度,因此
matchesSelector
call 返回 true,一切都化为一堆废话。
问题是在这种情况下 jQuery 无法与 Sizzle 正确交互。恭喜你,你是一只弹跳小虫子的骄傲的父亲。
这是一个(大量)jsfiddle,其中包含 jQuery 的内联版本,并有几个
console.log
调用来支持我上面所说的内容:需要注意的一些事项:
div span
和div span:nth-child(1)
得到合理的结果;它们都使用本机 Gecko 和 WebKit 选择器引擎。div span:first
、div span:last
甚至div span:eq(0 时,您都会得到相同的损坏结果);
;所有这三个都经过 Sizzle。Sizzle()
调用的四个参数版本未记录(请参阅 公共 API),所以我们不知道 jQuery 或 Sizzle 是否有问题。Allow me to expand on my comment a little bit. All of this is based on your second simplified example and jQuery 1.6.4. This is a little long winded perhaps but we need to walk through the jQuery code to find out what it is doing.
We do have the jQuery source available so let us go a wandering
through it and see what wonders there are to behold therein.
The guts of
siblings
looks like this:wrapped up in this:
And then
jQuery.sibling
is this:So we go up one step in the DOM, go to the parent's first child,
and continue sideways to get all of the parent's children (except
the node we started at!) as an array of DOM elements.
That leaves us with all of our sibling DOM elements in
ret
andnow to look at the filtering:
So what is
filter
all about?filter
is all about this:In your case,
elems
will have have exactly one element (as#d1
has one sibling) so we're off to
jQuery.find.matchesSelector
whichis actually
Sizzle.matchesSelector
:A bit of experimentation indicates that neither the Gecko nor WebKit
versions of
matchesSelector
can handlediv span:first
so we endup in the final
Sizzle()
call; note that both the Gecko and WebKitmatchesSelector
variants can handlediv span
and yourjsfiddles work as expected in the
div span
case.What does
Sizzle(expr, null, null, [node])
do? Why it returns an arraycontaining the
<span>
inside your<div>
of course. We'll havethis in
expr
:and this in
node
:So the
<span id="s1">
insidenode
nicely matches the selectorin
expr
and theSizzle()
call returns an array containing the<span>
and since that array has a non-zero length, thematchesSelector
call returns true and everything falls apart in a pile of nonsense.
The problem is that jQuery isn't interfacing with Sizzle properly in this case. Congratulations, you are the proud father of a bouncing baby bug.
Here's a (massive) jsfiddle with an inlined version of jQuery with a couple
console.log
calls to support what I'm talking about above:A few things to note:
div span
anddiv span:nth-child(1)
; both of these use the native Gecko and WebKit selector engine.div span:first
,div span:last
, and evendiv span:eq(0)
; all three of these go through Sizzle.Sizzle()
call that is being used not documented (see Public API) so we don't know if jQuery or Sizzle is at fault here.以此更新
});
检查小提琴示例
Update with this
});
Check Fiddle Example