web-dev-qa-db-fra.com

addClass et removeClass dans jQuery - ne supprime pas la classe

J'essaie de faire quelque chose de très simple. En gros, j'ai un "point chaud" div, sur lequel vous pouvez cliquer, qui remplit l'écran et affiche du contenu. J'y suis parvenu en changeant simplement la classe de div, en supprimant le mot "spot" et en ajoutant le mot "cultivé". Il existe une petite animation CSS pour le faire grandir. Cela fonctionne bien.

Le problème, c’est qu’au sein de cette division, il y a un close_button, qui pour le moment n’est que du texte. Je veux que cela change les classes - c’est-à-dire supprime les points développés et lus. Il ne fait pas cela lorsque vous cliquez dessus. Je pense que cela a à voir avec le fait que l'élément n'a pas ces classes lorsque le DOM est chargé, mais jQuery est un débutant et je ne sais pas comment contourner ce problème.

Je pense qu'il y a probablement une manière beaucoup plus sensée de le faire, quelqu'un pourrait-il me diriger dans la bonne direction? Je serais très reconnaissant. J'ai essayé d'utiliser toggleClass à la place, mais en vain.

$( document ).ready(function() {      
    $(".clickable").click(function() {  
        $(this).addClass("grown");  
        $(this).removeClass("spot");
    });   

    $(".close_button").click(function() {  
        alert (this);
        $("#spot1").removeClass("grown");  
        $("#spot1").addClass("spot");
    });   
});

MISE À JOUR:

J'utilise ce code maintenant,

$( document ).ready(function() {   
    $(document).on("click", ".close_button", function () { 
        alert ("oi");
        $("#spot1").addClass("spot");
        $("#spot1").removeClass("grown");
    });  


    $(document).on("click", ".clickable", function () {
        if ($(this).hasClass("spot")){
            $(this).addClass("grown");
            $(this).removeClass("spot");
        }
    });
});

étrangement, la fonction close_button n'ajoute toujours pas 'spot' ni ne supprimera 'cultivé' bien qu'elle ajoute d'autres classes et supprime d'autres classes ... J'ai ajouté la clause if car je pensais que les deux fonctions étaient déclenchées de la même manière. le temps, en se défaisant, mais cela ne semble faire aucune différence

28
rhinoceros1

Qu'est-ce qui se passe est que votre bouton de fermeture est placé à l'intérieur de votre .clickable div, donc l'événement click sera déclenché dans les deux éléments.

L'événement bouillonnant fera se propager l'événement click des nœuds enfants à leurs parents. Donc, votre .close_button callback sera exécuté en premier, et quand .clickable est atteint, il basculera à nouveau les classes. Comme cette course est très rapide, vous ne pouvez pas remarquer que les deux événements se sont produits.

                    / \
--------------------| |-----------------
| .clickable        | |                |
|   ----------------| |-----------     |
|   | .close_button | |          |     |
|   ------------------------------     |
|             event bubbling           |
----------------------------------------

Pour éviter que votre événement n'atteigne le .clickable, vous devez ajouter le paramètre event à votre fonction de rappel, puis appeler la méthode stopPropagation.

$(".close_button").click(function (e) { 
    $("#spot1").addClass("spot");
    $("#spot1").removeClass("grown");
    e.stopPropagation();
});

Violon: http://jsfiddle.net/u4GCk/1/

Plus d'infos sur l'ordre des événements en général: http://www.quirksmode.org/js/events_order.html (c'est là que j'ai choisi cette jolie ASCII art =] )

63
Guilherme Sehn

Le problème est dû à event bubbling . La première partie de votre code à ajouter .grown Fonctionne bien.

La deuxième partie "supprimer la classe développée" en cliquant sur le lien ne fonctionne pas comme prévu, car le gestionnaire pour .close_button Et .clickable Est exécuté. Donc, il supprime et lit la classe grown dans la classe div.

Vous pouvez éviter cela en utilisant e.stopPropagation() à l'intérieur du gestionnaire de clics .close_button Pour éviter que l'événement ne se répande.

DEMO: http://jsfiddle.net/vL8DP/

Code complet

$(document).on('click', '.clickable', function () {
   $(this).addClass('grown').removeClass('spot');
}).on('click', '.close_button', function (e) {
   e.stopPropagation();
   $(this).closest('.clickable').removeClass('grown').addClass('spot');
});
13

Chaque fois que je vois addClass et removeClass je pense pourquoi ne pas simplement utiliser toggleClass. Dans ce cas, nous pouvons supprimer le .clickable La classe pour éviter la propagation d’événement et éviter que l’événement ne soit déclenché sur tout ce que l’on clique à l’intérieur du .clickablediv.

$(document).on("click", ".close_button", function () { 
    $(this).closest(".grown").toggleClass("spot grown clickable");
});  

$(document).on("click", ".clickable", function () {
    $(this).toggleClass("spot grown clickable");
}); 

Je recommande également un wrapper parent pour votre .clickabledivs au lieu d'utiliser document. Je ne sais pas comment vous les ajoutez de manière dynamique, donc je ne voulais pas assumer votre mise en page pour vous.

http://jsfiddle.net/bplumb/ECQg5/2/

Bonne codage :)

7
Blake Plumb

Je recommanderais de mettre en cache les objets jQuery que vous utilisez plus d'une fois. Par exemple:

    $(document).on("click", ".clickable", function () {
        $(this).addClass("grown");
        $(this).removeClass("spot");
    });

serait:

    var doc = $(document);
    doc.on('click', '.clickable', function(){
       var currentClickedObject = $(this);
       currentClickedObject.addClass('grown');
       currentClickedObject.removeClass('spot');
    });

c'est en fait plus de code, MAIS c'est beaucoup plus rapide car vous n'avez pas à "parcourir" toute la bibliothèque jQuery pour obtenir l'objet $ (this).

4

Je pense que vous êtes presque là. Le problème est que votre $(this) dans le programme d'écoute du "bouton de fermeture" n'est pas le div sur lequel vous pouvez cliquer. Donc, vous voulez chercher en premier. essayez de remplacer $(this) par $(this).closest(".clickable"). Et n'oubliez pas la e.stopPropagation() comme le suggère Guilherme. cela devrait être quelque chose comme:

$( document ).ready(function() {   
    $(document).on("click", ".close_button", function () { 
        alert ("oi");
        e.stopPropagation()
        $(this).closest(".clickable").addClass("spot");
        $(this).closest(".clickable").removeClass("grown");
    });  


    $(document).on("click", ".clickable", function () {
        if ($(this).hasClass("spot")){
            $(this).addClass("grown");
            $(this).removeClass("spot");
        }
    });
});
3
thomasstephn

pourquoi ne pas le simplifier?

jquery

$('.clickable').on('click', function() {//on parent click
    $(this).removeClass('spot').addClass('grown');//use remove/add Class here because it needs to perform the same action every time, you don't want a toggle
}).children('.close_button').on('click', function(e) {//on close click
    e.stopPropagation();//stops click from triggering on parent
    $(this).parent().toggleClass('spot grown');//since this only appears when .grown is present, toggling will work great instead of add/remove Class and save some space
});

De cette façon, il est beaucoup plus facile de maintenir.

fait un violon: http://jsfiddle.net/filever10/3SmaV/

1
FiLeVeR10

Essaye ça :

$('.close-button').on('click', function(){
  $('.element').removeClass('grown');
  $('.element').addClass('spot');
});

$('.element').on('click', function(){
  $(this).removeClass('spot');
  $(this).addClass('grown');
});

J'espère avoir compris votre question.

1
lefoy

En fait, je viens de résoudre un problème que je rencontrais en inversant l'ordre dans lequel je modifiais les propriétés. Par exemple, je changeais d'abord l'attribut, mais je devais en fait supprimer la classe et ajouter la nouvelle classe avant de modifier les attributs. Je ne sais pas pourquoi cela a fonctionné, mais ça a fonctionné. Donc, quelque chose à essayer serait de changer de $("XXXX").attr('something').removeClass( "class" ).addClass( "newClass" ) à $("XXXX").removeClass( "class" ).addClass( "newClass" ).attr('something').

0
Zach Pedigo

Utilisez . On ()

vous avez besoin d'une délégation d'événements car ces classes ne sont pas présentes sur DOM lorsque celui-ci est prêt.

$(document).on("click", ".clickable", function () {
    $(this).addClass("grown");
    $(this).removeClass("spot");
});
$(document).on("click", ".close_button", function () {  
    $("#spot1").removeClass("grown");
    $("#spot1").addClass("spot");
});  

Je pense que le problème réside dans l'imbrication des éléments. Une fois que vous attachez un événement à l'élément externe, les clics sur les éléments internes déclenchent le même événement de clic pour l'élément externe. Donc, en fait, vous n'allez jamais dans le second état. Ce que vous pouvez faire est de vérifier l'élément cliqué. Et si c'est le bouton de fermeture, il faut éviter que la classe change. Voici ma solution:

var element = $(".clickable");
var closeButton = element.find(".close_button");
var onElementClick = function(e) {
    if(e.target !== closeButton[0]) {
        element.removeClass("spot").addClass("grown");
        element.off("click");
        closeButton.on("click", onCloseClick);
    }
}
var onCloseClick = function() {
    element.removeClass("grown").addClass("spot");
    closeButton.off("click");
    element.on("click", onElementClick);
}
element.on("click", onElementClick);

De plus, j'ajoute et supprime des gestionnaires d'événements.

JSFiddle -> http://jsfiddle.net/zmw9E/1/

0
Krasimir