J'essaie d'écrire un jeu de vidéo poker en Javascript afin d'en comprendre les bases, et j'ai rencontré un problème où les gestionnaires d'événements de clic jQuery se déclenchent plusieurs fois.
Ils sont attachés à des boutons pour placer un pari, et cela fonctionne très bien pour placer un pari sur la première main pendant un match (tirer une seule fois); mais dans les paris pour la trotteuse, l'événement de clic est déclenché deux fois à chaque fois qu'un bouton de pari ou de pari est enfoncé (le montant correct est donc doublé à chaque fois que vous appuyez). Dans l’ensemble, il suit ce modèle pendant le nombre de fois où l’événement clic est déclenché lorsqu’on appuie une fois sur un bouton de pari - où le terme ith de la séquence est pour le pari de la main ith depuis le début le jeu: 1, 2, 4, 7, 11, 16, 22, 29, 37, 46, qui semble être n (n + 1)/2 + 1 pour ce que ça vaut - et je n’étais pas assez intelligent pour comprendre cela, j'ai utilisé OEIS . :)
Voici la fonction avec les gestionnaires d’événements click qui agissent; j'espère que c'est facile à comprendre (laissez-moi savoir si ce n'est pas le cas, je veux m'améliorer aussi):
/** The following function keeps track of bet buttons that are pressed, until place button is pressed to place bet. **/
function pushingBetButtons() {
$("#money").text("Money left: $" + player.money); // displays money player has left
$(".bet").click(function() {
var amount = 0; // holds the amount of money the player bet on this click
if($(this).attr("id") == "bet1") { // the player just bet $1
amount = 1;
} else if($(this).attr("id") == "bet5") { // etc.
amount = 5;
} else if($(this).attr("id") == "bet25") {
amount = 25;
} else if($(this).attr("id") == "bet100") {
amount = 100;
} else if($(this).attr("id") == "bet500") {
amount = 500;
} else if($(this).attr("id") == "bet1000") {
amount = 1000;
}
if(player.money >= amount) { // check whether the player has this much to bet
player.bet += amount; // add what was just bet by clicking that button to the total bet on this hand
player.money -= amount; // and, of course, subtract it from player's current pot
$("#money").text("Money left: $" + player.money); // then redisplay what the player has left
} else {
alert("You don't have $" + amount + " to bet.");
}
});
$("#place").click(function() {
if(player.bet == 0) { // player didn't bet anything on this hand
alert("Please place a bet first.");
} else {
$("#card_para").css("display", "block"); // now show the cards
$(".card").bind("click", cardClicked); // and set up the event handler for the cards
$("#bet_buttons_para").css("display", "none"); // hide the bet buttons and place bet button
$("#redraw").css("display", "block"); // and reshow the button for redrawing the hand
player.bet = 0; // reset the bet for betting on the next hand
drawNewHand(); // draw the cards
}
});
}
S'il vous plaît, faites-moi savoir si vous avez des idées ou des suggestions, ou si la solution à mon problème est similaire à la solution d'un autre problème ici (j'ai examiné de nombreux threads portant le même titre et je n'ai pas eu la chance de trouver une solution qui puisse fonctionner. pour moi).
Pour vous assurer qu'un clic seulement les actions une fois utilisent ceci:
$(".bet").unbind().click(function() {
//Stuff
});
.unbind()
est obsolète et vous devriez plutôt utiliser la méthode .off()
. Appelez simplement .off()
juste avant d’appeler .on()
.
Cela supprimera tous les gestionnaires d'événements:
$(element).off().on('click', function() {
// function body
});
Pour supprimer uniquement les gestionnaires d'événements 'Cliquez' enregistrés:
$(element).off('click').on('click', function() {
// function body
});
Une meilleure option serait .one()
:
Le gestionnaire est exécuté au plus une fois par élément et par type d'événement.
$(".bet").one('click',function() {
//Your function
});
En cas de plusieurs classes et chaque classe doit être cliqué une fois,
$(".bet").on('click',function() {
//Your function
$(this).off('click'); //or $(this).unbind()
});
Si vous trouvez que .off () .unbind () ou .stopPropagation () ne résout toujours pas votre problème, essayez d’utiliser .stopImmediatePropagation () Fonctionne très bien dans les situations où vous souhaitez simplement que votre événement soit géré tout bouillonnement et sans effectuer aucun autre événement déjà en cours de traitement. Quelque chose comme:
$(".bet").click(function(event) {
event.stopImmediatePropagation();
//Do Stuff
});
fait le tour!
Si vous appelez cette fonction à chaque "clic", il s'agit de ajout / d'une autre paire de gestionnaires à chaque appel.
Ajouter des gestionnaires avec jQuery n’est tout simplement pas comme définir la valeur de l’attribut "onclick". On peut ajouter autant de gestionnaires que l'on veut.
c'est un vieux problème, mais j'y ai fait face aujourd'hui, et je pense que ma réponse aidera les futurs chercheurs de défis similaires.
il est exécuté plusieurs fois, car la fonction "on ('click', somefunction)" est appelée plusieurs fois et, par conséquent, elle est liée plusieurs fois. Pour résoudre ce problème de manière permanente, vous devez vous assurer que placez qu'il ne sera exécuté qu'une fois. après quoi, sur l'événement de clic de souris, la fonction ne sera déclenchée qu'une seule fois.
par exemple, si je mets "sur (" clic ", une fonction)" dans un endroit où il sera chargé deux fois, puis à chaque clic - "une fonction" sera déclenchée deux fois.
dans une séquence logique correcte, la fonction "off" ne doit être utilisée que lorsque vous avez vraiment l'intention de dissocier les événements. l'utiliser pour masquer les erreurs logiques dues au double chargement de la fonction "on" n'est pas une bonne approche, même si cela peut sembler fonctionner.
J'ai eu un problème à cause du balisage.
HTML:
<div class="myclass">
<div class="inner">
<div class="myclass">
<a href="#">Click Me</a>
</div>
</div>
</div>
jQuery
$('.myclass').on('click', 'a', function(event) { ... } );
Vous remarquez que j'ai la même classe "myclass" deux fois en HTML, donc il appelle click pour chaque instance de div.
Tous les trucs sur .on () et .one () sont excellents, et jquery est génial.
Mais parfois, vous voulez qu'il soit un peu plus évident que l'utilisateur ne soit pas autorisé à cliquer, et dans ces cas, vous pouvez faire quelque chose comme ceci:
function funName(){
$("#orderButton").prop("disabled", true);
// do a bunch of stuff
// and now that you're all done
setTimeout(function(){
$("#orderButton").prop("disabled",false);
$("#orderButton").blur();
}, 3000);
}
et votre bouton ressemblerait à ceci:
<button onclick='funName()'>Click here</button>
La meilleure option serait d’utiliser off
<script>
function flash() {
$("div").show().fadeOut("slow");
}
$("#bind").click(function() {
$( "body" )
.on("click", "#theone", flash)
.find("#theone")
.text("Can Click!");
});
$("#unbind").click(function() {
$("body")
.off("click", "#theone", flash)
.find("#theone")
.text("Does nothing...");
});
</script>
Dans mon cas, j'utilisais «délégué», donc aucune de ces solutions ne fonctionnait. Je crois que c’est le bouton qui apparaît plusieurs fois via des appels ajax qui était à l’origine du problème des clics multiples. La solution utilisait un délai d'expiration pour que seul le dernier clic soit reconnu:
var t;
$('body').delegate( '.mybutton', 'click', function(){
// clear the timeout
clearTimeout(t);
// Delay the actionable script by 500ms
t = setTimeout( function(){
// do something here
},500)
})
Nous devons stopPropagation()
afin d'éviter que Clicks déclenche trop souvent des événements.
$(this).find('#cameraImageView').on('click', function(evt) {
evt.stopPropagation();
console.log("Camera click event.");
});
Il empêche l’événement de remonter dans l’arborescence DOM, empêchant ainsi les gestionnaires parents d’être avertis de l’événement. Cette méthode n'accepte aucun argument.
Nous pouvons utiliser event.isPropagationStopped()
pour déterminer si cette méthode a déjà été appelée (sur cet objet événement).
Cette méthode fonctionne également pour les événements personnalisés déclenchés avec trigger (). Notez que cela n’empêche pas les autres gestionnaires du même élément de s’exécuter.
Cela se produit car l'événement est lié plusieurs fois au même élément.
La solution qui a fonctionné pour moi est la suivante:
Tuez tous les événements attachés en utilisant la méthode .die()
.
Et puis attachez votre méthode listener.
Ainsi,
$('.arrow').click(function() {
// FUNCTION BODY HERE
}
devrait être:
$('.arrow').die("click")
$('.arrow').click(function() {
// FUNCTION BODY HERE
}
Quand je traite de ce problème, j'utilise toujours:
$(".bet").unbind("click").bind("click", function (e) {
// code goes here
}
De cette façon, je dissocie et relie du même coup.
$(element).click(function (e)
{
if(e.timeStamp !== 0) // This will prevent event triggering more then once
{
//do your stuff
}
}
.one ne se déclenche qu'une fois pendant la durée de vie de la page
Donc, si vous voulez effectuer une validation, ce n'est pas la bonne solution, car si vous ne quittez pas la page après validation, vous ne revenez jamais. Mieux vaut utiliser
$(".bet").on('click',function()
{ //validation
if (validated) {
$(".bet").off('click'); //prevent to fire again when we are not yet off the page
//go somewhere
}
});
Une autre solution que j'ai trouvée était celle-ci, si vous avez plusieurs classes et que vous avez affaire à des boutons radio tout en cliquant sur l'étiquette.
$('.btn').on('click', function(e) {
e.preventDefault();
// Hack - Stop Double click on Radio Buttons
if (e.target.tagName != 'INPUT') {
// Not a input, check to see if we have a radio
$(this).find('input').attr('checked', 'checked').change();
}
});
https://jsfiddle.net/0vgchj9n/1/
Pour vous assurer que l'événement ne se déclenche qu'une seule fois, vous pouvez utiliser Jquery .one (). JQuery one garantit que votre gestionnaire d'événements n'appelle qu'une seule fois. De plus, vous pouvez inscrire votre gestionnaire d'événements avec un seul pour autoriser d'autres clics une fois le traitement de l'opération de clic en cours terminé.
<div id="testDiv">
<button class="testClass">Test Button</button>
</div>
…
var subscribeClickEvent = function() {$("#testDiv").one("click", ".testClass", clickHandler);};
function clickHandler() {
//... perform the tasks
alert("you clicked the button");
//... subscribe the click handler again when the processing of current click operation is complete
subscribeClickEvent();
}
subscribeClickEvent();
J'avais ce problème avec un lien généré dynamiquement:
$(document).on('click', '#mylink', function({...do stuff...});
J'ai trouvé que le remplacement de document
par 'body'
corrigeait le problème:
$('body').on('click', '#mylink', function({...do stuff...});
Dans mon cas, l’événement onclick se déclenche plusieurs fois car j’ai créé un gestionnaire d’événements générique comparativement à
`$('div').on("click", 'a[data-toggle="tab"]',function () {
console.log("dynamic bootstrap tab clicked");
var href = $(this).attr('href');
window.location.hash = href;
});`
changé en
`$('div#mainData').on("click", 'a[data-toggle="tab"]',function () {
console.log("dynamic bootstrap tab clicked");
var href = $(this).attr('href');
window.location.hash = href;
});`
et doivent également faire des gestionnaires distincts pour les clics statiques et dynamiques, pour l'onglet statique, cliquez sur
`$('a[data-toggle="tab"]').on("click",function () {
console.log("static bootstrap tab clicked");
var href = $(this).attr('href');
window.location.hash = href;
});`
Essayez comme ça:
<a href="javascript:void(0)" onclick="this.onclick = false; fireThisFunctionOnlyOnce()"> Fire function </a>
Dans mon cas, j'avais chargé deux fois le même fichier *.js
sur la page dans une balise <script>
; J'ai supprimé la déclaration en double et cela a résolu le problème.