Ereignis nur einmal binden

104

Ich habe folgenden Code:

function someMethod()
{
  $(obj).click(function {});
}

someMethod wird zweimal aufgerufen und daher wird das Klickereignis zweimal gebunden. Wie kann ich es nur einmal binden lassen?

Feuervogel
quelle
Mögliches Duplikat des JQuery-Ereignismodells und Verhinderung doppelter Handler
Cees Timmerman

Antworten:

190

Wenn Sie es anwenden können, möchten Sie wahrscheinlich einen Blick auf event.preventDefault und event.stopPropagation werfen ODER die Bindung jedes Mal innerhalb Ihrer Methode aufheben und binden

function someMethod()
{
  $(obj).off('click').on('click', function(e) {
    // put your logic in here 
  });
}
pna
quelle
19
Seien Sie vorsichtig, da dies ALLE Klickereignisse aufhebt und nicht immer erwünschtes Verhalten ist. Wenn Sie beispielsweise etwas an ein Dokument binden, möchten Sie nur dieses eine Ereignis aufheben, nicht alle.
Mārtiņš Briedis
26
Falls Sie nicht versehentlich andere Klickereignisse lösen möchten, sollten Sie function someMethod() { $(obj).off('click.namespace').on('click.namespace', function {}); }
Manu
@ Manu Sie von dieser Antwort
aexl
89

Zusätzlich zur Antwort von pna möchten Sie möglicherweise über den Namespace Ihres Ereignisses nachdenken, damit Sie nicht versehentlich alle Klickereignisse lösen.

Funktion someMethod () {
    $ (obj) .unbind ('click.namespace'). bind ('click.namespace', function () {});
}}

https://api.jquery.com/event.namespace/

Iain
quelle
10
Dies sollte die akzeptierte Antwort sein. Das Aufheben der Bindung aller Klickereignisse kann leicht zu Problemen führen - insbesondere, wenn es sich um ein komplexes Projekt mit viel jQuery handelt. Dank dafür! Wusste nichts von dieser einfachen Namespace-Lösung !!
Simon Steinberger
Mit der aktuellen jQuery sollte dies sein $(obj).off()und $(obj).on()jeweils. Ansonsten hat der Namespace geholfen und das hat funktioniert. Danke dir!
Aexl
19

Es gibt keine integrierte Methode, um festzustellen, ob Sie diese bestimmte Funktion bereits gebunden haben. Sie können mehrere Klickfunktionen an ein Objekt binden. Beispielsweise:

$('#id').bind('click', function(){
alert('hello');
});


$('#id').bind('click', function(){
alert('goodbuy');
});

Wenn Sie beim Klicken auf das Objekt die oben genannten Schritte ausführen, wird Hallo und dann auf Wiedersehen angezeigt. Um sicherzustellen, dass nur eine Funktion an das Klickereignis gebunden ist, lösen Sie die Bindung des Klickereignishandlers und binden Sie die gewünschte Funktion wie folgt:

$(obj).unbind('click').bind('click', function(){... });
Matt Paxton
quelle
12

Die naheliegende Lösung besteht darin, nicht someMethod()zweimal anzurufen . Wenn Sie das nicht beheben können, können Sie eine Statusvariable beibehalten, sodass sie immer nur einmal so gebunden wird:

function someMethod()
{
    if (!someMethod.bound) {
        $(obj).click(function() {});
        someMethod.bound = true;
    }
}

Hinweis: Hierbei wird eine Eigenschaft der Funktion selbst verwendet, anstatt eine globale Variable einzuführen, um zu verfolgen, ob sie gebunden wurde. Sie können auch eine Eigenschaft für das Objekt selbst verwenden.

Sie können sehen, dass es hier funktioniert: http://jsfiddle.net/jfriend00/VHkxu/ .

jfriend00
quelle
11

Oder verwenden Sie die one () -Funktion von jQuery, die on () ähnelt, das Ereignis jedoch nur einmal auslöst, selbst wenn Sie es mehrmals binden.

http://api.jquery.com/one/

xandrw
quelle
8
Manchmal hilft es. aber manchmal möchten Sie die Lösung, in der Sie können: EINMAL BEFESTIGEN, ABER VIELE VERWENDEN.
Rzassar
5

jQuery macht das Aufrufen einer Funktion nur einmal ziemlich einfach:

function someMethod()
{

     $(obj).click(function() {});
      this.someMethod = $.noop;
}
Esailija
quelle
1
Dies funktioniert nur, wenn someMethod eine Methode eines Objekts oder einer globalen Funktion ist.
Jcubic
jQuery.noopist nur ein Zeichen kürzer als function(){}, also ist es ein bisschen albern zu sagen, dass es hier "hilft" und nur eine leere Funktion bietet. Hier ist ein Nicht-jQuery-Nicht-Methoden-Beispiel für diese allgemeine Lösung:var fn = function(){ fn = function(){}; do stuff; };
1j01
1
@ 1j01 Bearbeitet, um $stattdessen zu verwenden
Esailija
2

Dies ist ein Vorschlag, da ich Ihre Logik nicht kenne. Kann oder kann nicht für Sie arbeiten.

Wenn Sie die Funktionen jquery live () und one () kombinieren, erhalten Sie ein besseres Ergebnis als bei Event-Rebinds.

Die Sonderfälle funktionieren, wenn Sie 2 DOM-Elemente (Eltern & Kind) haben. Live () am übergeordneten Knoten stellt sicher, dass das Ereignis aufgerufen wird, und ruft dann one () auf, um ein Ereignis dynamisch zu registrieren, das nur einmal ausgeführt wird. (Dies bietet ähnliche Funktionen wie Rebinds).

Bambus
quelle
One()Funktion funktionierte in chrome, aber nicht safariin Mac.
Halbblutprinz
2

Sie können den gebundenen Elementen eine CSS-Klasse hinzufügen und sie dann herausfiltern:

function someMethod()
{
    $(obj).not('.click-binded')
          .click(function {})
          .addClass('click-binded');
}

Diese Methode kann auch für Plugins verwendet werden:

  $(obj).not('.datetimepicker-applied')
        .datetimepicker()
        .addClass('datetimepicker-applied');
Bakyt Abdrasulov
quelle
1
var bound = false;

function someMethod()
{
    if(!bound)
    {
       $(obj).click(function {});
       bound = true;
    }
}

aber ich würde wahrscheinlich untersuchen, warum es zweimal aufgerufen wird, bevor ich eine Art Problemumgehung mache.

Kai Qing
quelle
3
Wenn Sie diesen Weg gehen, ziehen Sie die Lösung von jfriend00 in Betracht, boundan die someMethod()der globale Namensraum angehängt ist, anstatt ihn zu verschmutzen.
Nuala
1

Wenn Sie nur einmal an das Objekt binden möchten, sollten Sie ein Flag implementieren und sich an dieses Objekt halten.

Beispielsweise:

if($('#id') && $('#id').data('done') == null)) {
    $('#id').bind('click', function() {
        alert('hello');
    });

    $('#id').data('done', true);
}
cscan
quelle
1

Sie können diese jQuery-Erweiterungsfunktion verwenden.

$.fn.once = function (type, fn, uid) {
  if(uid == undefined) {
    console.error("Called $.once without uid\n", this, "\n", fn);
  }

  var dataStr = type+"-handler-"+uid;
  if(!this.data(dataStr)) {
    this.data(dataStr, true);
    this.on(type, fn);
  }
};

Anstatt dies zu tun

$("button").on("click", function(){
  alert("You Clicked On A Button");
});

Du machst das

$("button").once("click", function(){
  alert("You Clicked On A Button");
}, "btnHandler");

Jetzt, wenn ich eine Funktion habe

function addBtnHandler() {
  $("button").once("click", function() {
    alert("You Clicked On A Button");
  }, "btnHandler");
}

Und ich nenne es mehrmals

addBtnHandler();
addBtnHandler();
addBtnHandler();

Es macht es nur einmal.

Beachten Sie, dass die Erweiterung funktioniert, indem Sie sowohl die UID als auch den Typ überprüfen. Dies bedeutet, dass Sie verschiedene Arten von Handlern mit derselben UID binden können. Möglicherweise möchten Sie dies. Um es zu ändern, bearbeiten.

var dataStr = type+"-handler-"+uid;

Mit so etwas wie

var dataStr = "handler-"+uid;

Nathnolt
quelle
1

Ich habe auch versucht, die Methode off and on jquery zum Binden von Ereignissen nur einmal mit dem dom-Element zu verwenden, das noch nicht vorhanden ist oder das dom-Element noch nicht erstellt wurde.

$('.select').off('event').on('event', 'selector', function(e){ // });

Dieser Code funktionierte nicht richtig

Ich bin auf eine sehr lukrative Methode gestoßen, die eine Methode ist. Dies ist sehr nützlich, wenn Sie ein Ereignis nur einmal binden möchten.

Das Dokument finden Sie hier http://api.jquery.com/one/

Dies ist dasselbe wie die Methode 'on', unterscheidet sich jedoch in ihrem Verhalten, sich nicht an das Ereignis für mehrere Selektoren zu halten.

$('body').one('click', 'selector', function(){ // do your stuff here });
Ankit Vishwakarma
quelle
1

Sie können dies mit reinem JS erreichen, indem Sie die addEventListener- Methode und seine einmalige Option verwenden

target.addEventListener('click', handler, {once: true});
Skav
quelle
2
Dies führt dazu, dass das Ereignis nach einmaligem Klicken auf das Element nicht mehr gebunden wird. Dies löst nicht das Problem, dass Ereignisse mehrfach gebunden werden.
Top Cat