早些时候,我回答this question,这基本上是关于删除表格行。这个问题是关于该问题的评论的结果。给出以下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
)的兄弟姐妹,这是tr
中的最后一个table
”。显然,没有符合该描述的元素 - tr
中有table
,但它不是div
的兄弟。所以,我不希望返回任何元素。但是,它实际上返回整个表,就像它完全忽略选择器的tr:last
部分一样。
让我更加困惑的是,如果删除:last
伪选择器,它会按预期工作(不返回任何元素)。
为什么上面的代码删除了整个表格?我只是愚蠢而且缺少明显的东西吗?您可以在行动here中看到上述代码。
修改 - 这是一个简化版本。给出以下HTML:
<div id="d1"></div>
<div>
<span></span>
</div>
为什么以下jQuery返回第二个div
:
$("#d1").siblings("div span:last");
我希望它不返回任何内容,因为没有span
是#d1
的兄弟。 Here's a fiddle这个简化的例子。
更新
在@muistooshort的精彩调查之后,我创建了一个jQuery bug ticket来跟踪这个问题。
答案 0 :(得分:5)
请允许我稍微扩展我的评论。所有这些都基于您的第二个简化示例和jQuery 1.6.4。这可能有点冗长,但我们需要通过jQuery代码来了解它在做什么。
我们确实有jQuery源可用,所以让我们去徘徊 通过它,看看其中有什么奇迹。
siblings
的胆量如下:
siblings: function( elem ) {
return jQuery.sibling( elem.parentNode.firstChild, elem );
}
包含在此:
// `name` is "siblings", `fn` is the function above.
jQuery.fn[ name ] = function( until, selector ) {
var ret = jQuery.map( this, fn, until )
//...
if ( selector && typeof selector === "string" ) {
ret = jQuery.filter( selector, ret );
}
//...
};
然后jQuery.sibling
就是这样:
sibling: function( n, elem ) {
var r = [];
for ( ; n; n = n.nextSibling ) {
if ( n.nodeType === 1 && n !== elem ) {
r.push( n );
}
}
return r;
}
所以我们在DOM中迈出了一步,去了父母的第一个孩子, 并继续横向以获得所有父母的孩子(除了 我们开始的节点!)作为DOM元素的数组。
这使我们在ret
和ret = jQuery.filter( selector, ret );
中拥有了所有兄弟DOM元素
现在来看看过滤:
filter
那么filter
到底是什么? filter: function( expr, elems, not ) {
//...
return elems.length === 1 ?
jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :
jQuery.find.matches(expr, elems);
}
就是这个:
elems
在您的情况下,#d1
将只有一个元素(jQuery.find.matchesSelector
有一个兄弟姐妹)所以我们要去Sizzle.matchesSelector
实际上是var html = document.documentElement,
matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector;
//...
Sizzle.matchesSelector = function( node, expr ) {
// Make sure that attribute selectors are quoted
expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']");
if ( !Sizzle.isXML( node ) ) {
try {
if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) {
var ret = matches.call( node, expr );
// IE 9's matchesSelector returns false on disconnected nodes
if ( ret || !disconnectedMatch ||
// As well, disconnected nodes are said to be in a document
// fragment in IE 9, so check for that
node.document && node.document.nodeType !== 11 ) {
return ret;
}
}
} catch(e) {}
}
return Sizzle(expr, null, null, [node]).length > 0;
};
:
matchesSelector
一些实验表明Gecko和WebKit都没有
版本div span:first
可以处理Sizzle()
,因此我们结束了
在最后的matchesSelector
电话中;请注意Gecko和WebKit
div span
变体可以处理div span
和您的
jsfiddles在Sizzle(expr, null, null, [node])
案例中按预期工作。
<span>
做什么?为什么它返回一个数组
当然,在<div>
内包含expr
。我们会有
这在'div span:last'
:
node
,这在<div id="d2">
<span id="s1"></span>
</div>
:
<span id="s1">
因此node
内的expr
与选择器很匹配
在Sizzle()
中,<span>
调用返回一个包含该数组的数组
matchesSelector
由于该数组的长度不为零,console.log
呼叫返回true,一切都在废话中崩溃。
问题是在这种情况下jQuery没有正确地与Sizzle接口。恭喜你,你是一个蹦蹦跳跳的小虫子的骄傲之父。
这是一个(大规模)jsfiddle,带有内联版本的jQuery,有几个div span
调用来支持我上面所说的内容:
有几点需要注意:
div span:nth-child(1)
和div span:first
获得明智的结果;这两个都使用本机Gecko和WebKit选择器引擎。div span:last
,div span:eq(0)
甚至Sizzle()
相同的已损坏的结果;所有这三个都通过Sizzle。答案 1 :(得分:0)
使用此更新
$('.removelink').click(function(){
$(this).parent().siblings('table').find('tr:last').remove();
});