powiązać wydarzenie tylko raz

Odpowiedzi:

190

Jeśli możesz to zastosować, prawdopodobnie zechcesz rzucić okiem na event.preventDefault i event.stopPropagation LUB za każdym razem rozpinać i wiązać, w ramach Twojej metody, takiej jak

function someMethod()
{
  $(obj).off('click').on('click', function(e) {
    // put your logic in here 
  });
}
pna
źródło
19
Uważaj, ponieważ powoduje to odłączenie WSZYSTKICH kliknięć i nie zawsze jest to pożądane zachowanie. Na przykład, kiedy wiążesz coś z dokumentem, chcesz rozwiązać tylko jedno zdarzenie, a nie wszystkie.
Mārtiņš Briedis
26
Jeśli nie chcesz przypadkowo usuwać powiązań innych zdarzeń związanych z kliknięciami, możesz użyć function someMethod() { $(obj).off('click.namespace').on('click.namespace', function {}); }
Manu
@Manu skopiowałeś z tej odpowiedzi
aexl
89

Oprócz odpowiedzi pna możesz pomyśleć o utworzeniu przestrzeni nazw wydarzenia, aby nie omijać przypadkowo odłączania wszystkich zdarzeń kliknięcia.

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

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

Iain
źródło
10
To powinna być akceptowana odpowiedź. Odłączenie wszystkich zdarzeń kliknięcia może łatwo zepsuć sprawę - zwłaszcza jeśli jest to złożony projekt z dużą ilością jQuery. Dziękuję za to! Nie wiedziałem o tym prostym rozwiązaniu przestrzeni nazw !!
Simon Steinberger
Przy obecnym jQuery powinno to być odpowiednio $(obj).off()i $(obj).on(). W przeciwnym razie przestrzeń nazw pomogła i to zadziałało. Dziękuję Ci!
aexl
19

Nie ma wbudowanej metody określającej, czy ta konkretna funkcja została już powiązana. Do obiektu można przypisać wiele funkcji kliknięcia. Na przykład:

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


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

jeśli wykonasz powyższe czynności, gdy obiekt zostanie kliknięty, pojawi się ostrzeżenie „cześć”, a następnie „żegnaj”. Aby upewnić się, że tylko jedna funkcja jest powiązana ze zdarzeniem kliknięcia, odłącz moduł obsługi zdarzenia kliknięcia, a następnie powiąż żądaną funkcję w następujący sposób:

$(obj).unbind('click').bind('click', function(){... });
Matt Paxton
źródło
12

Oczywistym rozwiązaniem jest nie dzwonienie someMethod()dwa razy. Jeśli nie możesz tego naprawić, możesz zachować zmienną stanu, aby wiązała się tylko raz w ten sposób:

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

Uwaga: to używa właściwości samej funkcji zamiast wprowadzania zmiennej globalnej, aby śledzić, czy została powiązana. Możesz również użyć właściwości na samym obiekcie.

Możesz zobaczyć, jak działa tutaj: http://jsfiddle.net/jfriend00/VHkxu/ .

jfriend00
źródło
11

Lub użyj funkcji one () jQuery, która jest podobna do on (), ale uruchamia zdarzenie tylko raz, nawet jeśli powiążesz je wiele razy.

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

xandrw
źródło
8
Czasami to pomaga. ale czasami potrzebujesz rozwiązania, w którym możesz: PRZYŁĄCZAĆ RAZ, ALE UŻYWAĆ WIELE.
Rzassar
5

jQuery sprawia, że ​​wywołanie niektórych funkcji jest możliwe tylko raz:

function someMethod()
{

     $(obj).click(function() {});
      this.someMethod = $.noop;
}
Esailija
źródło
1
To zadziała tylko wtedy, gdy someMethod jest metodą obiektu lub funkcją globalną.
jcubic
jQuery.noopjest tylko o jeden znak krótszy niż function(){}, więc głupio jest mówić, że „pomaga”, po prostu udostępnia pustą funkcję. Oto przykład tego rozwiązania ogólnego, który nie jest var fn = function(){ fn = function(){}; do stuff; };
oparty na
1
@ 1j01 Zmienione do użycia $zamiast tego
Esailija
2

To jest sugestia, ponieważ nie znam twojej logiki. Może lub nie zadziała dla Ciebie.

Spróbuj połączyć funkcje live () jquery i one (), aby uzyskać lepszy wynik niż ponowne wiązanie zdarzeń.

Specjalne przypadki działają, gdy masz 2 elementy DOM (nadrzędny i podrzędny). Funkcja Live () w węźle nadrzędnym zapewnia wywołanie zdarzenia, a następnie wywołuje metodę one (), aby dynamicznie zarejestrować zdarzenie, które zostanie wykonane tylko raz. (zapewnia to podobną funkcjonalność jak ponowne wiązania).

Bambus
źródło
One()funkcja działała, chromeale nie działała safariw Mac.
Książę Półkrwi
2

Możesz dodać klasę css do powiązanych elementów, a następnie je odfiltrować:

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

Ta metoda może być również używana dla wtyczek:

  $(obj).not('.datetimepicker-applied')
        .datetimepicker()
        .addClass('datetimepicker-applied');
Bakyt Abdrasulov
źródło
1
var bound = false;

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

ale prawdopodobnie sprawdziłbym, dlaczego tak się dzieje; jest wywoływany dwa razy, zanim wykonam jakieś obejście.

Kai Qing
źródło
3
Jeśli idziesz w ten sposób, rozważ rozwiązanie jfriend00, w którym boundjest dołączone someMethod()zamiast zanieczyszczać globalną przestrzeń nazw.
nuala
1

Jeśli chcesz połączyć się z obiektem tylko raz, zaimplementuj flagę i trzymaj się tego obiektu.

Na przykład:

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

    $('#id').data('done', true);
}
cscan
źródło
1

Możesz użyć tej funkcji rozszerzenia jQuery.

$.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);
  }
};

Zamiast tego robić

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

Zrób to

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

Teraz, kiedy mam wokół tego funkcję

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

I nazywam to wiele razy

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

Robi to tylko raz.

Zauważ, że rozszerzenie działa, sprawdzając zarówno uid, jak i type. Oznacza to, że możesz wiązać różne typy programów obsługi z tym samym UID, możesz tego chcieć lub nie. Aby to zmienić, edytuj.

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

Coś w rodzaju

var dataStr = "handler-"+uid;

nathnolt
źródło
1

Próbowałem też użyć metody włączania i wyłączania jquery do powiązania zdarzenia tylko raz z elementem dom, który jeszcze nie istnieje lub element dom nie został jeszcze utworzony.

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

Ten kod nie działał poprawnie

Natknąłem się na bardzo lukratywną metodę, którą jest metoda „jedna”. Jest to bardzo przydatne, gdy chcesz powiązać wydarzenie tylko raz.

Dokument można znaleźć tutaj http://api.jquery.com/one/

Jest to to samo, co metoda „włączona”, ale różni się jej zachowaniem i nie pozwala na trzymanie się zdarzenia dla wielu selektorów.

$('body').one('click', 'selector', function(){ // do your stuff here });
Ankit Vishwakarma
źródło
1

Można to osiągnąć z czystym JS, używając addEventListener sposób i jego raz opcję

target.addEventListener('click', handler, {once: true});
Skav
źródło
2
Powoduje to, że zdarzenie staje się niezwiązane po jednokrotnym kliknięciu elementu. To nie rozwiązuje problemu wielokrotnego wiązania wydarzeń.
Top Cat