37 votes

jQuery est trop verbeux, voudrais des conseils sur la façon de faire plus court

J'ai quelques jQuery code que je voudrais examens et des pointeurs sur comment mettre sa ligne de compte à rebours et raccourcir.

$('#p1').click(function() {
    $('#list').fadeOut(450);
    $('#q1').delay(600).fadeIn(450)
});
$('#p2').click(function() {
    $('#list').fadeOut(450);
    $('#q2').delay(600).fadeIn(450)
});
$('#p3').click(function() {
    $('#list').fadeOut(450);
    $('#q3').delay(600).fadeIn(450)
});
$('#p4').click(function() {
    $('#list').fadeOut(450);
    $('#q4').delay(600).fadeIn(450)
});

...

$('#p12').click(function() {
    $('#list').fadeOut(450);
    $('#q12').delay(600).fadeIn(450)
});
$('#p13').click(function() {
    $('#list').fadeOut(450);
    $('#q13').delay(600).fadeIn(450)
});

Peut ce code sera mieux optimisé? Ou, au moins, fait moins verbeux?

68voto

Xion Points 11130

Vous pouvez utiliser un for boucle, mais assurez-vous que le compteur de boucle, la valeur est dans un domaine approprié pour click gestionnaire d'événements:

var clickHandler = function(k) {
    return function() {
        $('#list').fadeOut(450);
        $('#q' + k).delay(600).fadeIn(450);
    };
};
for (var i = 1; i < 14; ++i) {
    $('#p' + i).click(clickHandler(i));
}

Sinon, l' delay et fadeIn serait appliquée à l' #q13 élément exclusivement, depuis le compteur réelles (avec sa valeur finale de 13 ans) est en la fermeture.


EDIT: Depuis beaucoup de réponses a mal ici, je vais essayer d'expliquer plus précisément ce qui se passe dans ce code, comme cela semble être assez déroutant.

La solution "naturelle" avec l'injection du gestionnaire de clic directement dans la boucle serait le suivant:

for(var i = 1; i < 14; i++) {
    $('#p'+i).click(function() {
        $('#list').fadeOut(450);
        $('#q'+i).delay(600).fadeIn(450)
    });
}

Mais ce n'est pas du tout équivalent à la forme allongée, qui répertorie tous les 13 variantes l'un après l'autre. Le problème est que, s'il y a en effet de 13 fonctions de créés ici, ils sont tous fermés au cours de la même variable i, dont la valeur change. Il arrive enfin à la valeur de 13 et la boucle se termine.

Quelques temps plus tard les fonctions liées à l' #p1...#p13 éléments sont appelés (lorsque l'un de ces éléments est cliqué) et ils utilisent cette valeur finale de l' i. Il en résulte que dans #q13 animés.

Ce qui doit être fait ici est de faire quelque chose appelé lambda de levage et d'éliminer la variable indépendante i, dont la valeur est inadvertly changé. Une technique courante consiste à fournir une usine de fonction", qui accepte de la valeur pour nos variables et les sorties d'une fonction que nous allons utiliser en tant que gestionnaire d'événements:

var clickHandler = function(k) {
    return function() {
        $('#list').fadeOut(450);
        $('#q' + k).delay(600).fadeIn(450);
    };
};

Puisque la portée de l' k paramètre local d' clickHandler, de chaque appel d' clickHandler obtient différente k variable. La fonction retourné à partir de clickHandler est donc fermé sur différentes variables, qui peuvent à leur tour avoir des valeurs différentes. C'est exactement ce dont nous avons besoin. On peut alors appeler clickHandler de notre boucle, en lui passant la valeur du compteur:

for (var i = 1; i < 14; ++i) {
    $('#p' + i).click(clickHandler(i));
}

J'espère que ce qui fait la différence un peu plus clair.


EDIT: Comme Esailija souligné dans les commentaires, il est également possible d'utiliser jQuery.each afin d'obtenir le même effet:

$.each(new Array(13), function(idx) {
    $('#p' + (idx + 1)).click(function() {
        $('#list').fadeOut(450);
        $('#q' + idx).delay(600).fadeIn(450);
    });
});

C'est probablement la solution de choix si vous êtes déjà au courant de la fermeture/portée du problème que j'ai essayé de décrire ci-dessus.

14voto

lonesomeday Points 95456

La solution idéale, de l'OMI, contrairement à la accepté de répondre, n'est pas à la base de votre code autour des relations entre id valeurs, mais à la base c'autour des relations dans les DOM. jQuery fournit vous avec un index méthode, qui permet de voir où en est votre élément est en relation avec ses frères et sœurs. Vous pouvez ensuite utiliser cette valeur pour sélectionner la autre élément à afficher.

Ce n'est, bien sûr, que vous la structure de votre code HTML dans une manière sémantique. Par exemple:

<div id="list">
    <a href="#">Link 1</a>
    <a href="#">Link 2</a>
    <a href="#">Link 3</a>
    <a href="#">Link 4</a>
    <a href="#">Link 5</a>
    <a href="#">Link 6</a>
    <a href="#">Link 7</a>
    <a href="#">Link 8</a>
</div>
<div id="questions"> <!-- perhaps this is what q stands for... -->
    <div>1 ...</div>
    <div>2 ...</div>
    <div>3 ...</div>
    <div>4 ...</div>
    <div>5 ...</div>
    <div>6 ...</div>
    <div>7 ...</div>
    <div>8 ...</div>
</div>

Le premier lien s'applique à la première imbriquée div, la deuxième pour la seconde, etc. Le balisage est simple, facile à lire et clairement sémantique.

Votre code peut ensuite être très simple, pas besoin de s'inquiéter sur les usines. En effet, la plus belle façon de le faire est avec remontée d'événements et de délégation, géré admirablement par du jQuery on méthode (en 1.7; avant cela, utilisez delegate).

$('#list').on('click', 'a', function() {
    $('#list').fadeOut(450);
    $('#questions div').eq($(this).index()).delay(600).fadeIn(450);
});

Travail jsFiddle (je sais que l'animation a l'air un peu maladroit, désolé.)

$(this).index() trouve la relation de l'élément courant par rapport à ses frères et sœurs. .eq() filtres de la sélection (de #questions div - éléments) pour trouver l'élément dans la position correspondante.

Le code peut ne pas être assez rapide (si vous utilisez id valeurs, il sera presque certainement être légèrement plus rapide), mais la marge est plus simple et donc plus robuste.

12voto

Esailija Points 74052

Si vous devez insister sur les pas d'événement à l'aide de délégation et les classes alors:

$.each( new Array(13), function(index){
    $('#p'+(index+1) ).click(function() {
        $('#list').fadeOut(450);
        $('#q'+(index+1)).delay(600).fadeIn(450)
    });
});

À l'aide de classes et de la délégation:

$( document ).delegate( ".my-class", "click", function(){
var idIndex = this.id.match( /\d+$/, )[0];

        $('#list').fadeOut(450);
            $('#q'+idIndex).delay(600).fadeIn(450)

});

6voto

Abdul Munim Points 9039

Comme d'autres, vous pouvez utiliser un for-loop pour ce faire, mais vous êtes en réalité englobante-vous 14 ps et chaque fois que vous ajoutez un nouveau p vous avez besoin pour augmenter votre for-loop condition de test.

C'est ce que je ferais:

$("[id^=p]").bind("click", function() {
    $('#list').fadeOut(450);
    $('#q' + $(this).attr("id").match(/^#p(\d+)$/i)[1]).delay(600).fadeIn(450)
})

5voto

Thilo Points 108673

Ne pourriez-vous utiliser une classe à la place de tous ces identifiants différents? Et puis un peu de navigation pour trouver le correspondant d'un autre élément?

$('.myCoolEffect').click(function(event) {
    $('#list').fadeOut(450);
    // find the matching element based on this on somehow
    $(event.currentTarget).up(1).delay(600).fadeIn(450);
});

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X