2010-03-17 10 views
12

Il jQuery documentation per i .toggle() metodo afferma:Alternativa al metodo .toggle() di jQuery che supporta eventData?

Il metodo .toggle() è previsto per convenienza. È relativamente semplice implementare lo stesso comportamento a mano e questo può essere necessario se le ipotesi incorporate in .toggle() si dimostrano limitanti.

Le ipotesi integrate in .toggle hanno dimostrato limitante per il mio compito attuale, ma la documentazione non elaborare su come implementare lo stesso comportamento. Devo passare eventData alle funzioni del gestore fornite a toggle(), ma sembra che solo .bind() supporterà questo, non .toggle().

La mia prima inclinazione è quella di utilizzare un flag globale per una funzione di gestore singolo per memorizzare lo stato del clic. In altre parole, piuttosto che:

$('a').toggle(function() { 
    alert('odd number of clicks'); 
}, function() { 
    alert('even number of clicks'); 
}); 

fare questo:

var clicks = true; 
$('a').click(function() { 
    if (clicks) { 
    alert('odd number of clicks'); 
    clicks = false; 
    } else { 
    alert('even number of clicks'); 
    clicks = true; 
    } 
}); 

Non ho ancora testato il secondo, ma ho il sospetto che avrebbe funzionato. È questo il modo migliore per fare qualcosa del genere, o c'è un modo migliore che mi manca?

Grazie!

+0

Non capisco la tua domanda. Cosa stai cercando di fare? – cletus

+0

@cletus: non riesco a utilizzare .toggle() perché non sembra supportare il passaggio di eventData alla funzione del gestore. Sto cercando la migliore soluzione alternativa che supporti eventData, che (per quanto mi consta) sarà basato sul metodo .bind(). In altre parole, dove la documentazione di jQuery dice "è relativamente semplice implementare lo stesso comportamento a mano", sto cercando di fare proprio questo. – Bungle

risposta

35

Sembra un modo ragionevole per farlo ... Vorrei solo suggerire di utilizzare le utilità data storage di jQuery invece di introdurre una variabile extra (che potrebbe diventare un mal di testa se si volesse tenere traccia di un intero gruppo di collegamenti). Quindi, sulla base del vostro esempio:

$('a').click(function() { 
    var clicks = $(this).data('clicks'); 
    if (clicks) { 
    alert('odd number of clicks'); 
    } else { 
    alert('even number of clicks'); 
    } 
    $(this).data("clicks", !clicks); 
}); 
+0

Grazie, Alconja - buona risposta! Apprezzo l'esempio di codice conciso. – Bungle

+0

Hmm .. al primo clic non viene eseguito ... – LazerSharks

+0

@Gnuey - Funziona per me al primo clic (copia/incolla questa fonte esatta nella mia console Firebug e ora tutti i link di questa pagina attivano gli avvisi per primi). Stai vedendo un errore o semplicemente non stai attento? – Alconja

2

Ecco un plugin che implementa alternativa al .toggle(), soprattutto perché è stato rimosso in jQuery 1.9+.

Come usare:

La firma di questo metodo è:

.cycle(functions [, callback] [, eventType]) 
  • functions [Array]: Una serie di funzioni per scorrere tra
  • callback [Funzione]: Una funzione che verrà eseguita al termine di ogni iterazione. Verrà passato l'iterazione corrente e l'output della funzione corrente. Può essere usato per fare qualcosa con il valore di ritorno di ogni funzione nell'array functions.
  • eventType [Stringa]: una stringa che specifica i tipi di eventi da attivare, ad es. "click mouseover"

Un esempio di utilizzo è:

$('a').cycle([ 
    function() { 
     alert('odd number of clicks'); 
    }, function() { 
     alert('even number of clicks'); 
    } 
]); 

ho incluso una dimostrazione here.

codice del plugin:

(function ($) { 
    if (!Array.prototype.reduce) { 
     Array.prototype.reduce = function reduce(accumulator) { 
      if (this === null || this === undefined) throw new TypeError("Object is null or undefined"); 
      var i = 0, 
       l = this.length >> 0, 
       curr; 

      if (typeof accumulator !== "function") // ES5 : "If IsCallable(callbackfn) is false, throw a TypeError exception." 
      throw new TypeError("First argument is not callable"); 

      if (arguments.length < 2) { 
       if (l === 0) throw new TypeError("Array length is 0 and no second argument"); 
       curr = this[0]; 
       i = 1; // start accumulating at the second element 
      } else curr = arguments[1]; 

      while (i < l) { 
       if (i in this) curr = accumulator.call(undefined, curr, this[i], i, this); 
       ++i; 
      } 

      return curr; 
     }; 
    } 
    $.fn.cycle = function() { 
     var args = Array.prototype.slice.call(arguments).reduce(function (p, c, i, a) { 
      if (i == 0) { 
       p.functions = c; 
      } else if (typeof c == "function") { 
       p.callback = c; 
      } else if (typeof c == "string") { 
       p.events = c; 
      } 
      return p; 
     }, {}); 
     args.events = args.events || "click"; 
     console.log(args); 
     if (args.functions) { 
      var currIndex = 0; 

      function toggler(e) { 
       e.preventDefault(); 
       var evaluation = args.functions[(currIndex++) % args.functions.length].apply(this); 
       if (args.callback) { 
        callback(currIndex, evaluation); 
       } 
       return evaluation; 
      } 
      return this.on(args.events, toggler); 
     } else { 
      //throw "Improper arguments to method \"alternate\"; no array provided"; 
     } 
    }; 
})(jQuery);