2010-01-19 12 views
16

Es überraschte mich, dass Sizzle (die Selektor-Engine jQuery verwendet) kommt mit einem eingebauten :nth-child() Selektor, aber fehlt ein :nth-of-type() Selektor.: nth-of-type() in jQuery/Sizzle?

Um die Differenz zwischen :nth-child() und :nth-of-type() zu illustrieren und um das Problem zu veranschaulichen, betrachten the following HTML document:

<!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> 

Da Sizzle die Browser-native querySelector() und querySelectorAll() Methoden verwendet, wenn diese vorhanden sind (dh in Browsern implementieren, die bereits die Selectors API), Zeug wie $('body p:nth-child'); wird natürlich funktionieren. In älteren Browsern funktioniert es jedoch nicht, da Sizzle für diesen Selektor keine Fallback-Methode bietet.

Ist es möglich, einfach den :nth-of-type() Selektor zu Sizzle hinzuzufügen oder ihn in jQuery zu implementieren (unter Verwendung von the built-in :nth-child() selector, vielleicht)? A custom selector with parameters wäre nett.

+2

Nicht sicher, aber wird '$ (' p: even ') 'dir nicht geben, wonach du suchst? Sie haben bereits den Selektor ('p'), also müssen Sie ihn nur filtern. – Kobi

+1

@Kobi: Es ist nicht so einfach. Der Selektor 'p: nth-child (2n)' würde jedem zweiten Absatz * in jedem Elternelement * entsprechen. Wenn es zwei DIVs gibt, die beide drei Absätze enthalten, würden die folgenden Absätze (in DOM-Reihenfolge) mit "p: nth-child (2n)" übereinstimmen: # 2, # 5. Sehen? Es geht nicht nur darum, jedes "P" in das Dokument zu bekommen und es dann auf jedes * mn * te Element zu filtern. Ja, '$ ('p: even')' ist ein Alias ​​für '$ ('p: nth-child (2n)')' ', aber nicht für' $ ('p: nth-of-type (2n) ")". Außerdem verwende ich '2n' in diesem Beispiel, aber natürlich sollten auch andere Variationen möglich sein. –

+0

Habe es und löschte meine Antwort. – Kobi

Antwort

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; 
}; 

Test case - (Check in IE oder benennen Sie die Wähler)

Sie können natürlich hinzufügen sogar & ungerade zu:

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

+1

Cool! Das ist, was ich gesucht habe; eine kurze, clevere, prägnante Lösung. Wie Sie wissen, werden ': odd 'und': even 'bereits in jQuery unterstützt, nur nicht in der': n-ten-of-type (odd) '/': n-ten-of-type (even) 'Form, aber es ist Schön, dass sie da sind, der Vollständigkeit halber. –

+0

Update: für noch mehr Selektoren, siehe https://github.com/keithclark/JQuery-Extended-Selectors –

+1

Schön, aber ich wollte nur andere über diese Lösung warnen immer eine Periodizität (n) vorausgesetzt. Ich meine, Filter wie ': n-Typ (2n)' und ': n-Typ (2)' werden gleich sein (wenn letzterer nur das zweite Element sein sollte, anstatt aller geraden Elemente) . –

1

Ich kann nicht so tun, als ob nth-of-type implementiert ist, aber jQuery bietet einen Mechanismus, mit dem Sie Ihren eigenen benutzerdefinierten Selektor erstellen können.

Die folgenden Fragen befasst sich mit benutzerdefinierten Selektoren und kann einen nützlichen Einblick Ihnen

What useful custom jQuery selectors have you written?

+0

Ja, ich bin mir dessen bewusst ... Ich sollte das wahrscheinlich zu meinem Beitrag hinzufügen. –

4

das Plugin jQuery bieten moreSelectors Unterstützung für n-of-Typ (und viele andere Wähler) hat. Ich schlage vor, entweder das zu verwenden oder einfach ein einfaches Plugin zu implementieren, das nur die exakten Selektoren implementiert, die Sie benötigen. Sie sollten Code von dort kopieren und einfügen können.

Happy hacken!