JQuery: Comment sélectionner "de ici jusqu'au prochain H2"?

Je crée une page de FAQ très simple avec jQuery. Ainsi:

<h2>What happens when you click on this question?</h2> <p>This answer will appear!</p> 

Ceci est tout dans une division très spécifique, alors je vais sélectionner l'en-tête avec $('#faq h2') . Simple, n'est-ce pas? Cliquez sur le H2, et utilisez this.next() pour afficher le paragraphe suivant.

(La mise en garde avec cette page est qu'un non-programmeur le maintiendra, c'est pourquoi je n'utilise pas les classes: il n'y a aucune garantie que les nouvelles entrées aient les bonnes classes.)

Alors! Le problème:

 <h2>What happens when you click on the next question?</h2> <p>That is an interesting conundrum.</p> <p>Because the maintainer is kind of long-winded</p> <p>and many answers will span a few paragraphs.</p> 

Donc comment, sans ajouter des div et des classes et quoi, puis-je avoir ma routine this.next() sélectionnez tout entre la question-that-was-clicked-on et la question suivante (en-tête H2)?

Un problème intéressant. D'abord, permettez-moi de dire que je pense que la meilleure stratégie est de joindre toute la réponse dans un div et ensuite le problème devient trivial à résoudre:

 <h2>Question here</h2> <div> <p>Answer here</p> </div> </h2>Next Question</h2> ... 

avec:

 $(function() { $("h2").click(function() { $(this).next().toggleClass("highlighted"); }); }); 

Mais cela étant dit, il est résolu sans cela.

 $(function() { $("h2").click(function() { $(this).nextAll().each(function() { if (this.tagName == 'H2') { return false; // stop execution } $(this).toggleClass("highlighted"); }); }); }); 

Pas suprêmement élégant, mais ça marchera.

Note: Cela suppose que les questions sont des frères et sœurs. S'ils ne le sont pas, cela devient beaucoup plus compliqué.

Je me rends compte que c'est une vieille question, mais jQuery 1.4 a maintenant le prochain . Donc, quelque chose comme ça devrait maintenant fonctionner:

 $('h2').click(function(){ $(this).nextUntil('h2').show(); }) 

Ne serait-il pas plus logique d'utiliser une liste DLL de style css?

 <dl class="faq"> <dt>Question?</dt> <dd> <p>Answer</p> <p>Answer</p> <p>Answer</p> </dd> </dl> 

Ensuite, sélectionnez facilement en utilisant:

 $('+ dd', this); 

Ceci étant la sélection dt actuelle.

Ou simplement envelopper chaque réponse dans un div, car il est logique sémantiquement aussi. Cependant, je pense qu'une liste DL a beaucoup plus de sens sémantiquement.

Sûr! Il suffit de faire une boucle de temps.

 $('h2').click(function() { var next = $(this).next(); while (next.length != 0 && next[0].nodeName == 'P') { next.toggle(); next = next.next(); } }); 

Cela suppose que vous n'avez que des balises p après votre h2. Vous pouvez ajouter d'autres exceptions à la boucle while si vous souhaitez ajouter quelque chose comme img.

Ou si vous ne vous souciez pas de ce qui se trouve entre les balises H2, vous pouvez vérifier que ce n'est pas égal à H2.

 $('h2').click(function() { var next = $(this).next(); while (next.length != 0 && next[0].nodeName != 'H2') { next.toggle(); next = next.next(); } }); 

Cela cachera tout après le H2 qui est cliqué jusqu'à ce que le prochain H2 soit trouvé ou que vous remontez un niveau dans le dom.

Peut-être que cela ne répond pas vraiment à votre question, mais vous pouvez envelopper chaque élément de FAQ (c'est-à-dire chaque paire question / réponse) dans un élément DIV . Cela aurait du sens sémantiquement, et le non-programmeur qui maintiendrait la page aurait tout simplement à copier un DIV complet (pas besoin de cours).

HTML:

 <div id="faq"> <!-- start FAQ item --> <div> <h2>Question goes here</h2> <p>Answer goes here.</p> <p>And here.</p> <ul> <li>Really, use any HTML element you want here.</li> <li>It will work.</li> </ul> </div> <!-- end FAQ item --> <!-- start FAQ item --> <div> <h2>Second question goes here</h2> <p>Answer to question two.</p> </div> <!-- end FAQ item --> </div> 

JavaScript (jQuery):

 $('#faq div h2').click(function() { $(this).parent().find(':not(h2)').show(); }); 

Juste au cas où il y a encore des gens qui ont besoin d'une réponse pour cela … Cela inclut également la ligne H2 dans le groupe.

Ici, si l'échantillon html pour lequel ma solution fonctionne:

 <h2> text1 </h2> <p>asd</p> <p>asd</p> <p>asd</p> <p>asd</p> <h3>kjdf</h3> <h2>asdk</h2> <h3>kjdf</h3> <p>asd</p> <p>asd</p> <p>asd</p> <p>asd</p> <h2>aqdsa</h2> 

Solution:

 jQuery( function ( $ ) { //defining groups for wrapping them in custom divs $('h2').each( function () { var grpForDiv= []; var next = $(this).next(); grpForDiv.push(this); while ( next.length!==0 && next!== undefined && next[0].nodeName !== 'H2') { grpForDiv.push(next[0]); next = next.next(); } jQuery(grpForDiv).wrapAll('<div class="Group1" />'); } ); } ); 

Notez que la réponse sélectionnée est bonne, mais je cherche à faire quelque chose de similaire, donc j'ai travaillé trop longtemps sur 🙂

Je l'ai mis dans un exemple.

Donné HTML:

 <h2>Question 1</h2> <p>Answer 1</p> <p>Answer 1</p> <p>Answer 1</p> <h2>Question 2</h2> <p>Answer 2</p> <p>Answer 2</p> <p>Answer 2</p> <h2>Question 3</h2> <p>Answer 3</p> <p>Answer 3</p> <p>Answer 3</p> 

Faites ce qui suit et vous obtiendrez votre réponse. Je pense que c'est maintenant la plus élégante de toutes les solutions proposées, mais j'aimerais bien apprécier les autres.

 jQuery.fn.nextUntilMatch = function(selector) { var result = []; for(var n=this.next();(n.length && (n.filter(selector).length == 0));n=n.next()) result.push(n[0]); return $(result); } $(function() { $('h2~p').hide(); $('h2').click(function() { $(this).nextUntilMatch(':not(p)').toggle(); }) }); 

Vous pouvez également le faire sans modifier HTML. C'est un plugin que je viens d'écrire pour ce but particulier:

 (function($){ $.fn.nextUntill = function(expr){ var helpFunction = function($obj, expr){ var $siblings = $obj.nextAll(); var end = $siblings.index( $siblings.filter(expr) ); if(end===-1) return $([]); return $siblings.slice(0, end); } var retObject = new Array(); this.each(function(){ $.merge(retObject, helpFunction($(this), expr)); }); return $(retObject); } })(jQuery); 

Vous pouvez l'utiliser comme ceci:

  $('h2').click(function(){ $(this).nextUntill('h2').show(); //this will show all P tags between the clicked h2 and the next h2 assuiming the p and h2 tags are siblings }); 

Je ne pense pas que votre stratégie pour résoudre le problème est correcte, vous avez 6 réponses qui résistent en partie à votre problème …..

Mais votre plus grand problème est que vous dites que vous ne pouvez pas faire confiance aux mainteneurs pour utiliser divs / spans / classes, etc.

Ce que je pense que vous devriez faire, c'est de simplifier le processus pour eux et de les former à utiliser votre méthode ou il ne fonctionnera PAS .

Ajoutez une légère marquage de votre choix et interprétez-les.

 [Q] What happens when you click this link?[/Q] [A] This marvellous answer appears [/A] 

(JQuery ne corrige pas le bogue 'utilisateur')