animação addClass / removeClass com jQuery

226

Estou usando jQuery e jQuery-ui e quero animar vários atributos em vários objetos.

Para explicar o problema aqui, simplifiquei-o para uma div que muda de azul para vermelho quando o usuário passa o mouse sobre ele.

Consigo obter o comportamento que desejo ao usar animate(), no entanto, ao fazê-lo, os estilos que estou animando devem estar no código de animação e, portanto, são separados da minha folha de estilos. (veja o exemplo 1 )

Uma alternativa é usar addClass()e removeClass()mas eu não tenho sido capaz de recriar o comportamento exato que eu possa começar com animate(). (veja o exemplo 2 )


Exemplo 1

Vamos dar uma olhada no código que tenho com animate():

$('#someDiv')
  .mouseover(function(){
    $(this).stop().animate( {backgroundColor:'blue'}, {duration:500});
  })
  .mouseout(function(){
    $(this).stop().animate( {backgroundColor:'red'}, {duration:500});
  });

exibe todos os comportamentos que estou procurando:

  1. Anima suavemente entre vermelho e azul.
  2. Nenhuma animação é “superaquecida” quando o usuário move o mouse rapidamente para dentro e para fora da div.
  3. Se o usuário mover o mouse para fora / para dentro enquanto a animação ainda estiver sendo reproduzida, será facilitada corretamente entre o estado atual 'meio caminho' e o novo estado 'objetivo'.

Mas, como as mudanças de estilo são definidas animate(), preciso alterar os valores de estilo e não posso apontar apenas para a minha folha de estilo. Essa 'fragmentação' de onde os estilos são definidos é algo que realmente me incomoda.


Exemplo 2

Aqui está minha melhor tentativa atual de usar addClass()e removeClass(observe que, para que a animação funcione, você precisa do jQuery-ui):

//assume classes 'red' and 'blue' are defined

$('#someDiv')
  .addClass('blue')
  .mouseover(function(){
    $(this).stop(true,false).removeAttr('style').addClass('red', {duration:500});
  })
  .mouseout(function(){
    $(this).stop(true,false).removeAttr('style').removeClass('red', {duration:500});
  });

Isso exibe as propriedades 1. e 2. dos meus requisitos originais, no entanto 3 não funciona.

Eu entendo o motivo disso:

Ao animar addClass()e o removeClass()jQuery adiciona um estilo temporário ao elemento e, em seguida, incrementa os valores apropriados até atingirem os valores da classe fornecida, e somente então ele realmente adiciona / remove a classe.

Por isso, tenho que remover o atributo style, caso contrário, se a animação for interrompida até a metade, o atributo style permanecerá e sobrescreverá permanentemente quaisquer valores de classe, pois os atributos de estilo em uma tag têm maior importância do que os estilos de classe.

No entanto, quando a animação está no meio do caminho, ela ainda não adicionou a nova classe; portanto, com esta solução, a cor salta para a cor anterior quando o usuário move o mouse antes da conclusão da animação.


O que eu quero idealmente é ser capaz de fazer algo assim:

$('#someDiv')
  .mouseover(function(){
    $(this).stop().animate( getClassContent('blue'), {duration:500});
  })
  .mouseout(function(){
    $(this).stop().animate( getClassContent('red'), {duration:500});
  });

Onde getClassContentapenas retornaria o conteúdo da classe fornecida. O ponto principal é que, dessa forma, não preciso manter minhas definições de estilo em todo o lugar, mas posso mantê-las nas classes da minha folha de estilo.

Johannes
fonte
1
Quais versões do IE você precisa suportar? Você ficaria feliz com o IE9? Ou você precisa apoiar mais baixo?
tw16 5/09/11
1
Não estou nem aí para o IE, para ser sincero. Tudo isso foi testado apenas com navegadores webkit (safari / chrome).
Johannes
como getClassContenté a aparência?
sreginogemoh

Respostas:

311

Como você não está preocupado com o IE, por que não usar transições css para fornecer a animação e o jQuery para alterar as classes. Exemplo ao vivo: http://jsfiddle.net/tw16/JfK6N/

#someDiv{
    -webkit-transition: all 0.5s ease;
    -moz-transition: all 0.5s ease;
    -o-transition: all 0.5s ease;
    transition: all 0.5s ease;
}
tw16
fonte
14
A partir de 12/06/2015, isso é suportado no - IE 10+ - Chrome 26+ - FireFox 16+ - Safari 6.1+ - Opera 12.1+ -webkit, -moz, -o é necessário apenas para navegadores ainda mais antigos. Você provavelmente pode deixar de fora para economizar espaço.
CLST
3
@clst, eu preferiria compatibilidade retroativa com navegadores antigos do que economizar alguns bytes de espaço.
Arman H
96

Outra solução (mas requer o jQueryUI, como apontado por Richard Neil Ilagan nos comentários): -

addClass, removeClass e toggleClass também aceitam um segundo argumento; o tempo de duração de um estado para outro.

$(this).addClass('abc',1000);

Veja jsfiddle: - http://jsfiddle.net/6hvZT/1/

Omar Tariq
fonte
28
Observe que isso requer a interface do usuário do jQuery. O jQuery pronto para uso não suporta interpolação de animação para xxxClass()funções.
Richard Neil Ilagan
@ Richard Neil Ilagan: Obrigado por notificar. Eu realmente senti falta desse ponto.
Omar Tariq
4
Você pode indicar qual arquivo baixar e incluir no arquivo .html para que eu possa usar o jQueryUI apenas para xxxClassinterpolação de animação dessa maneira?
nitrato de sódio
[jqueryui.com] (jqueryui.com) @snitrato de sódio
joe_young
1
Essa solução também não é animada da mesma maneira que slide () ou animada (). O valor de milissegundos é um atraso, que não é uma animação.
Solona Armstrong
38

Você pode usar jquery ui's switchClass, Heres um exemplo:

$( "selector" ).switchClass( "oldClass", "newClass", 1000, "easeInOutQuad" );

Ou veja este jsfiddle .

by0
fonte
1
-1. Você não atendeu às restrições 1, 2 e 3 listadas na postagem original. Especificamente, switchClass trata mal os requisitos 2 e 3.
Johannes
12

Você só precisa do núcleo de efeitos da interface do usuário do jQuery (13 KB), para permitir a duração da adição (assim como Omar Tariq apontou)

Patrick
fonte
5

Eu estava olhando para isso, mas queria ter uma taxa de transição diferente para entrar e sair.

Isto é o que acabei fazendo:

//css
.addedClass {
    background: #5eb4fc;
}

// js
function setParentTransition(id, prop, delay, style, callback) {
    $(id).css({'-webkit-transition' : prop + ' ' + delay + ' ' + style});
    $(id).css({'-moz-transition' : prop + ' ' + delay + ' ' + style});
    $(id).css({'-o-transition' : prop + ' ' + delay + ' ' + style});
    $(id).css({'transition' : prop + ' ' + delay + ' ' + style});
    callback();
}
setParentTransition(id, 'background', '0s', 'ease', function() {
    $('#elementID').addClass('addedClass');
});

setTimeout(function() {
    setParentTransition(id, 'background', '2s', 'ease', function() {
        $('#elementID').removeClass('addedClass');
    });
});

Isso instantaneamente muda a cor do plano de fundo para # 5eb4fc e depois volta lentamente ao normal por mais de 2 segundos.

Aqui está um violino

Tj Gienger
fonte
2

Embora a pergunta seja bastante antiga, estou adicionando informações que não estão presentes em outras respostas.

O OP está usando stop () para interromper a animação atual assim que o evento for concluído. No entanto, o uso da combinação certa de parâmetros com a função deve ajudar. por exemplo. stop (true, true) ou stop (true, false), pois isso afeta bem as animações na fila.

O link a seguir ilustra uma demonstração que mostra os diferentes parâmetros disponíveis com stop () e como eles diferem de finish ().

http://api.jquery.com/finish/

Embora o OP não tenha tido problemas ao usar o JqueryUI, isso é para outros usuários que podem encontrar cenários semelhantes, mas não podem usar o JqueryUI / precisam também oferecer suporte ao IE7 e 8.

Anurag
fonte