2011-12-07 17 views
83

Ho il seguente codice:evento si legano solo una volta

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

someMethod viene chiamato due volte e quindi fare clic su evento è rilegato due volte. Come posso farlo legare solo una volta?

+0

possibile duplicato del [modello di evento JQuery e prevenire i gestori duplicati] (http: // StackOverflow .com/questions/2180326/jquery-event-model-and-prevention-duplicate-handlers) –

risposta

155

Se è possibile applicarlo, probabilmente vuole dare un'occhiata a event.preventDefault e event.stopPropagation OR slegare e legare ogni volta, all'interno del vostro metodo come

function someMethod() 
{ 
    $(obj).off('click').on('click', function(e) { 
    // put your logic in here 
    }); 
} 
+13

Fai attenzione, perché questo non genera TUTTI gli eventi click, e non è sempre il comportamento desiderato. Ad esempio, quando si associa qualcosa a un documento, si desidera separare solo quell'evento, non tutti. –

+13

Nel caso in cui non si vuole svincolare accidentalmente altri eventi click, si potrebbe desiderare di utilizzare 'funzione someMethod() { $ (obj) .OFF ('click.namespace'). On ('click.namespace' , funzione {}); } – Manu

+0

Soluzione eccellente. –

12

La soluzione ovvia è non chiamare someMethod() due volte. Se non è possibile rimediare, allora si può mantenere una variabile di stato in modo che sempre e solo una volta si lega in questo modo:

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

Nota: questo utilizza una proprietà della funzione stessa, piuttosto che l'introduzione di una variabile globale per tenere traccia se è stato legato. Puoi anche usare una proprietà sull'oggetto stesso.

Si può vedere funziona qui: http://jsfiddle.net/jfriend00/VHkxu/.

1
var bound = false; 

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

ma probabilmente guarderei perché è stato chiamato due volte prima di fare una sorta di soluzione alternativa.

+3

Se stai andando in questo modo, considera la soluzione di jfriend00 dove 'bound' è collegato a' someMethod() 'invece di inquinare lo spazio dei nomi globale . – yoshi

5

jQuery rende chiamare una qualche funzione possibile solo una volta abbastanza facile:

function someMethod() 
{ 

    $(obj).click(function() {}); 
     this.someMethod = $.noop; 
} 
+1

Funzionerà solo se someMethod è il metodo di un oggetto o di una funzione globale. – jcubic

+0

'jQuery.noop' ​​è solo un carattere più corto di' function() {} ', quindi è un po 'sciocco dire che sta" aiutando "qui, fornendo solo una funzione vuota. Ecco un esempio non-jQuery non-metodo di questa soluzione generale: 'var fn = function() {fn = function() {}; fare cose; }; ' – 1j01

+1

@ 1j01 Modificato per usare' $ 'invece – Esailija

19

Non esiste un metodo integrato per determinare se è già stata associata questa particolare funzione. È possibile associare più funzioni di clic a un oggetto. Per esempio:

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


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

se si fa quanto sopra quando l'oggetto viene cliccato avviserà ciao allora addio. Per assicurarsi che solo una funzione è destinata a l'evento click non associare il gestore di eventi click quindi associare la funzione desiderata in questo modo:

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

Oltre alla risposta di PNA che si potrebbe desiderare di pensare a namespacing il vostro evento in modo da non lo fai andare in giro per non accoppiare accidentalmente tutti gli eventi click.

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

http://docs.jquery.com/Namespaced_Events

+8

Questa dovrebbe essere la risposta accettata. Unbinding * all * click events può rompere facilmente le cose, specialmente se si tratta di un progetto complesso con un sacco di jQuery in corso. Grazie per quello! Non sapevo di questa semplice soluzione namespace !! –

2

Questo è un suggerimento dato che non conosco la tua logica. Potrebbe o potrebbe non funzionare per te.

Prova a combinare jquery live() e una() funzione ti darà un risultato migliore rispetto all'evento rebind.

I casi speciali funzionano quando sono presenti 2 elementi DOM (genitore & child). Live() sul nodo padre si assicura che l'evento venga richiamato e quindi chiama uno() per registrare dinamicamente l'evento che verrebbe eseguito una sola volta. (questo fornisce funzionalità simili come rebinds).

+0

'Una funzione'() 'ha funzionato in' chrome' ma non ha funzionato in 'safari' in' Mac'. –

6

Oppure utilizzare la funzione one() di jQuery che è simile a on() ma attiva l'evento una sola volta, anche se lo si associa più volte.

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

+5

A volte aiuta. ma a volte vuoi la soluzione in cui puoi: ATTACCARE UNA VOLTA MA UTILIZZARE MOLTI. – Rzassar

1

Se si desidera associare all'oggetto una sola volta, è necessario implementare una bandiera e attenersi a tale oggetto.

Ad esempio:

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

    $('#id').data('done', true); 
} 
0

È possibile aggiungere classe CSS agli elementi associato, quindi filtrare fuori:

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

Questo metodo può essere utilizzato anche per i plugin:

$(obj).not('.datetimepicker-applied') 
     .datetimepicker() 
     .addClass('datetimepicker-applied'); 
0

È possibile utilizzare questa funzione di estensione 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); 
    } 
}; 

Invece di fare questo

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

Ya fare questo

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

Ora, quando ho una funzione intorno ad esso

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

E io chiamarlo più volte

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

Lo fa solo una volta.

Si noti che l'estensione funziona controllando sia l'uid che il tipo. Ciò significa che puoi associare diversi tipi di gestori con lo stesso uid, puoi o non vuoi questo. Per modificarlo, modifica.

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

con qualcosa di simile

var dataStr = "handler-"+uid;

1

ero anche cercando di utilizzare e spegnere il metodo di jQuery per il legame evento solo una volta con l'elemento DOM che non esiste ancora o dom l'elemento non è stato ancora creato.

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

Questo codice non funzionava correttamente

mi sono imbattuto in un metodo molto redditizio che è il metodo di 'uno'. È molto utile quando vuoi associare un evento solo una volta.

È possibile trovare il documento qui http://api.jquery.com/one/

Questo è lo stesso metodo di 'on', ma diverso con il suo comportamento con non attaccare con l'evento per più selettori.

$('body').one('click', 'selector', function(){ // do your stuff here }); 
0

È possibile raggiungere questo obiettivo con puro JS, utilizzando addEventListener metodo e la sua volta opzione

target.addEventListener('click', handler, {once: true}); 
Problemi correlati