jQuery / Sizzle中的:nth-of-type()是什么?

16

我很惊讶Sizzle(jQuery使用的选择器引擎)带有内置的:nth-child()选择器,但缺少:nth-of-type()选择器。

为了说明:nth-child():nth-of-type()之间的区别并说明问题,请考虑以下HTML文档

<!doctype html>
<html>
 <head>
  <meta charset="utf-8">
  <title>:nth-of-type() in Sizzle/jQuery?</title>
  <style>
   body p:nth-of-type(2n) { background: red; }
  </style>
 </head>
 <body>
  <p>The following CSS is applied to this document:</p>
  <pre>body p:nth-of-type(2n) { background: red; }</pre>
  <p>This is paragraph #1.</p>
  <p>This is paragraph #2. (Should be matched.)</p>
  <p>This is paragraph #3.</p>
  <p>This is paragraph #4. (Should be matched.)</p>
  <div>This is not a paragraph, but a <code>div</code>.</div>
  <p>This is paragraph #5.</p>
  <p>This is paragraph #6. (Should be matched.)</p>
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
  <script>
   $(function() {
    // The following should give every second paragraph (those that had red backgrounds already after the CSS was applied) an orange background.
    // $('body p:nth-of-type(2n)').css('background', 'orange');
   });
  </script>
 </body>
</html>

由于Sizzle使用浏览器本地的querySelector()querySelectorAll()方法(如果在已实现选择器API的浏览器中存在),因此像$('body p:nth-child');这样的东西当然可以工作。但是在旧版浏览器中无法工作,因为Sizzle没有此选择器的回退方法。
是否可以轻松地将:nth-of-type()选择器添加到Sizzle中,或者在jQuery中实现它(例如通过使用内置的:nth-child()选择器)?带有参数的自定义选择器会很好。

2
不确定,但是 $('p:even') 不是已经给你想要的结果了吗?你已经有了选择器 (p),所以你只需要过滤它即可。 - Kobi
1
@Kobi:这并不容易。选择器 p:nth-child(2n) 会匹配每个父元素中的每个第二个段落。如果有两个 DIV,都包含三个段落,则以下段落(按 DOM 顺序)将被 p:nth-child(2n) 匹配:#2、#5。明白了吗?这不仅仅是获取文档中的每个 P,然后将其过滤为每个 mnth 元素。 是的,$('p:even')$('p:nth-child(2n)') 的别名,但不是 $('p:nth-of-type(2n)') 的别名。此外,在此示例中我使用了 2n,但当然也应该有其他变化。 - Mathias Bynens
明白了,我已经删除了我的回答。 - Kobi
2
Nick Craver,就像我在帖子中解释的那样,这是因为Firefox是具有选择器API本地实现的浏览器之一。Sizzle不知道:nth-of-type()选择器,但Firefox的querySelectorAll()知道。这就是为什么它“起作用”的原因,但这并不是由于Sizzle。如果在Sizzle中加入这个功能,那么它将在所有浏览器中都能够工作,这将是很好的。 - Mathias Bynens
1
你知道吗,它没有被实现只是因为John Resig认为它不值得实现 - BoltClock
显示剩余3条评论
3个回答

14
/**
 * Return true to include current element
 * Return false to exclude current element
 */
$.expr[':']['nth-of-type'] = function(elem, i, match) {
    if (match[3].indexOf("n") === -1) return i + 1 == match[3];
    var parts = match[3].split("+");
    return (i + 1 - (parts[1] || 0)) % parseInt(parts[0], 10) === 0;
};

测试用例 -(在IE中检查或重命名选择器

当然,您也可以添加偶数和奇数

match[3] = match[3] == "even" ? "2n" : match[3] == "odd" ? "2n+1" : match[3];


1
太棒了!这正是我一直在寻找的:一个简短、聪明、简洁的解决方案。正如你所知,:odd:even已经在jQuery中得到支持,只是没有以:nth-of-type(odd)/ :nth-of-type(even)的形式出现,但为了完整起见,将它们加入其中也是不错的选择。 - Mathias Bynens
更新:更多选择器请参见 https://github.com/keithclark/JQuery-Extended-Selectors。 - Mathias Bynens
1
不错,但我只是想警告其他人关于这个解决方案总是假定有一个周期性(n)。我的意思是,像:nth-of-type(2n):nth-of-type(2)这样的过滤器将是相同的(当后者应该只是第二个元素,而不是所有偶数元素)。 - Mariano Desanze

4
jQuery插件moreSelectors支持nth-of-type(和许多其他选择器)。我建议使用它,或者只实现您需要的确切选择器的简单插件。您应该能够从那里复制粘贴代码。

祝愉快的编程!


1

我不敢说我知道nth-of-type是如何实现的,但是jQuery提供了一个机制,让你可以创建自己的自定义选择器。

下面这个问题涉及到自定义选择器,可能会为你提供有用的见解

你编写过哪些有用的自定义jQuery选择器?


是的,我知道这个问题... 我应该把它加到我的帖子中。 - Mathias Bynens

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接