jQuery clique / alternar entre duas funções

Eu estou procurando uma maneira de ter duas operações / funções / “blocos de código” separadas executadas quando algo é clicado e então um bloco totalmente diferente quando a mesma coisa é clicada novamente. Eu coloquei isso junto. Eu queria saber se havia uma maneira mais eficiente / elegante. Eu sei sobre jQuery .toggle (), mas é uma droga.

Trabalhando aqui: http://jsfiddle.net/reggi/FcvaD/1/

var count = 0; $("#time").click(function() { count++; //even odd click detect var isEven = function(someNumber) { return (someNumber % 2 === 0) ? true : false; }; // on odd clicks do this if (isEven(count) === false) { $(this).animate({ width: "260px" }, 1500); } // on even clicks do this else if (isEven(count) === true) { $(this).animate({ width: "30px" }, 1500); } }); 

jQuery tem dois methods chamados .toggle() . O outro [docs] faz exatamente o que você deseja para events de cliques.

Nota: Parece que, pelo menos desde o jQuery 1.7 , esta versão do .toggle está obsoleta , provavelmente exatamente por esse motivo, ou seja, que existem duas versões. Usar o .toggle para alterar a visibilidade dos elementos é apenas um uso mais comum. O método foi removido no jQuery 1.9 .

Abaixo está um exemplo de como se poderia implementar a mesma funcionalidade de um plugin (mas provavelmente expõe os mesmos problemas que a versão embutida (veja o último parágrafo na documentação)).


 (function($) { $.fn.clickToggle = function(func1, func2) { var funcs = [func1, func2]; this.data('toggleclicked', 0); this.click(function() { var data = $(this).data(); var tc = data.toggleclicked; $.proxy(funcs[tc], this)(); data.toggleclicked = (tc + 1) % 2; }); return this; }; }(jQuery)); 

DEMO

(Isenção de responsabilidade: não digo que esta é a melhor implementação! Aposto que pode ser melhorada em termos de desempenho)

E então chame com:

 $('#test').clickToggle(function() { $(this).animate({ width: "260px" }, 1500); }, function() { $(this).animate({ width: "30px" }, 1500); }); 

Atualização 2:

Nesse meio tempo, criei um plugin adequado para isso. Aceita um número arbitrário de funções e pode ser usado para qualquer evento. Pode ser encontrado no GitHub .

DEMO

documentação .one () .

Estou muito atrasado para responder, mas acho que é o código mais curto e pode ajudar.

 function handler1() { alert('First handler: ' + $(this).text()); $(this).one("click", handler2); } function handler2() { alert('Second handler: ' + $(this).text()); $(this).one("click", handler1); } $("div").one("click", handler1); 

DEMO Com o Código de Op

 function handler1() { $(this).animate({ width: "260px" }, 1500); $(this).one("click", handler2); } function handler2() { $(this).animate({ width: "30px" }, 1500); $(this).one("click", handler1); } $("#time").one("click", handler1); 

Micro jQuery Plugin

Se você quiser o seu próprio método clickToggle jQuery, você pode fazer como:

DEMO

 jQuery.fn.clickToggle = function(a,b) { function cb(){ [b,a][this._tog^=1].call(this); } return this.on("click", cb); }; 

 $("selector").clickToggle(function() { // Do something here }, function() { // Do thething here }); // (you can chain here other jQuery methods) 

Funções simples Toggler

DEMONSTRAÇÃO AO VIVO

 function a(){ console.log('a'); } function b(){ console.log('b'); } $("selector").click(function() { return (this.tog = !this.tog) ? a() : b(); }); 

Se você quiser ainda mais curto ( por que um, certo ?! ) você pode usar o operador do Bitwise XOR * Docs como:
DEMO

  return (this.tog^=1) ? a() : b(); 

Isso é tudo.
O truque é definir to this Object uma propriedade boolean tog e alterná-la usando negation ( tog = !tog )
e colocar as chamadas de function necessárias em um Operador Condicional ?:


No exemplo do OP (mesmo com vários elementos) poderia parecer com:

 function a(el){ $(el).animate({width: 260}, 1500); } function b(el){ $(el).animate({width: 30}, 1500); } $("selector").click(function() { var el = this; return (el.t = !el.t) ? a(el) : b(el); }); 

TAMBÉM : Você também pode armazenar -thagle como:
DEMO :

 $("selector").click(function() { $(this).animate({width: (this.tog ^= 1) ? 260 : 30 }); }); 

mas não foi o pedido exato do OP para ele está looking for a way to have two separate operations / functions


Usando Array.prototype.reverse :

Nota : isto não irá armazenar o estado atual do Toggle, mas apenas inverter as posições das nossas funções em Array (ele tem seus usos …)

Você simplesmente armazena suas funções a, b dentro de uma matriz, ao clicar , basta inverter a ordem da matriz e executar a function array[1] :

DEMONSTRAÇÃO AO VIVO

 function a(){ console.log("a"); } function b(){ console.log("b"); } var ab = [a,b]; $("selector").click(function(){ ab.reverse()[1](); // Reverse and Execute! // >> "a","b","a","b"... }); 

ALGUM MASHUP!

jQuery DEMO
JavaScript DEMO

Crie uma function legal toggleAB() que contenha suas duas funções, coloque-as em Array e, no final da matriz, simplesmente execute a function [ 0 // 1 ], respectivamente, dependendo da propriedade tog que é passada para a function a partir da this referência:

 function toggleAB(){ var el = this; // `this` is the "button" Element Obj reference` return [ function() { console.log("b"); }, function() { console.log("a"); } ][el.tog^=1](); } $("selector").click( toggleAB ); 

Eu faria algo assim para o código que você mostrou, se tudo que você precisa fazer é alternar um valor:

 var oddClick = true; $("#time").click(function() { $(this).animate({ width: oddClick ? 260 : 30 },1500); oddClick = !oddClick; }); 

Eu usei isso para criar um efeito de alternância entre duas funções.

 var x = false; $(element).on('click', function(){ if (!x){ //function x = true; } else { //function x = false; } }); 

Eu não acho que você deve implementar o método de alternância, pois há uma razão pela qual ele foi removido do jQuery 1.9.

Considere usar toggleClass em vez disso, que seja totalmente suportado pelo jQuery:

 function a(){...} function b(){...} 

Digamos, por exemplo, que seu acionador de evento seja onclick, então:

Primeira opção:

 $('#test').on('click', function (event) { $(this).toggleClass('toggled'); if ($(this).hasClass('toggled')) { a(); } else{ b(); } } 

Você também pode enviar as funções do manipulador como parâmetros:

Segunda opçao:

 $('#test').on('click',{handler1: a, handler2: b}, function (event) { $(this).toggleClass('toggled'); if ($(this).hasClass('toggled')) { event.data.handler1(); } else{ event.data.handler2(); } } 

Se tudo o que você está fazendo é manter um booleano isEven então você pode considerar verificar se uma class isEven está no elemento e então alternar essa class.

Usar uma variável compartilhada como contagem é uma espécie de prática ruim. Pergunte a si mesmo qual é o escopo dessa variável, pense se você tinha 10 itens que você gostaria de alternar em sua página, você criaria 10 variables, ou uma matriz ou variables ​​para armazenar seu estado? Provavelmente não.

Editar:
jQuery tem um método switchClass que, quando combinado com hasClass pode ser usado para animar entre as duas larguras que você definiu. Isso é favorável porque você pode alterar esses tamanhos posteriormente em sua folha de estilos ou adicionar outros parâmetros, como cor de fundo ou margem, à transição.

Use algumas funções e um booleano. Aqui está um padrão, não código completo:

  var state = false, oddONes = function () {...}, evenOnes = function() {...}; $("#time").click(function(){ if(!state){ evenOnes(); } else { oddOnes(); } state = !state; }); 

Ou

  var cases[] = { function evenOnes(){...}, // these could even be anonymous functions function oddOnes(){...} // function(){...} }; var idx = 0; // should always be 0 or 1 $("#time").click(function(idx){cases[idx = ((idx+1)%2)]()}); // corrected 

(Note que o segundo está fora da minha cabeça e eu misturo muito as linguagens, então a syntax exata não é garantida. Deve estar perto do Javascript real.)

modificando a primeira resposta você pode trocar entre n funções:

        my stupid example