animando addClass / removeClass con jQuery

226

Estoy usando jQuery y jQuery-ui y quiero animar varios atributos en varios objetos.

Para explicar el problema aquí, lo he simplificado a un div que cambia de azul a rojo cuando el usuario pasa el mouse sobre él.

Puedo obtener el comportamiento que quiero cuando uso animate(), sin embargo, al hacerlo, los estilos que estoy animando deben estar en el código de animación y, por lo tanto, están separados de mi hoja de estilos. (ver ejemplo 1 )

Se está utilizando una alternativa addClass()y removeClass()no he podido recrear el comportamiento exacto con el que puedo obtener animate(). (ver ejemplo 2 )


Ejemplo 1

Echemos un vistazo al código que tengo con animate():

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

Muestra todos los comportamientos que estoy buscando:

  1. Anima suavemente entre rojo y azul.
  2. No hay animación 'sobrecargando' cuando el usuario mueve su mouse rápidamente dentro y fuera del div.
  3. Si el usuario mueve su mouse hacia afuera / adentro mientras la animación aún se está reproduciendo, se alivia correctamente entre el estado actual 'a mitad de camino' y el nuevo estado 'objetivo'.

Pero dado que los cambios de estilo están definidos animate(), tengo que cambiar los valores de estilo allí, y no puedo hacer que apunte a mi hoja de estilo. Esta "fragmentación" de dónde se definen los estilos es algo que realmente me molesta.


Ejemplo 2

Aquí está mi mejor intento actual usando addClass()y removeClass(tenga en cuenta que para que funcione la animación necesita 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});
  });

Esto exhibe la propiedad 1. y 2. de mis requisitos originales, sin embargo, 3 no funciona.

Entiendo la razón de esto:

Al animar addClass()y removeClass()jQuery agrega un estilo temporal al elemento, y luego incrementa los valores apropiados hasta que alcanzan los valores de la clase proporcionada, y solo entonces realmente agrega / elimina la clase.

Debido a esto, tengo que eliminar el atributo de estilo, de lo contrario, si la animación se detiene a la mitad, el atributo de estilo permanecerá y sobrescribirá permanentemente cualquier valor de clase, ya que los atributos de estilo en una etiqueta tienen mayor importancia que los estilos de clase.

Sin embargo, cuando la animación está a mitad de camino, todavía no ha agregado la nueva clase, por lo que con esta solución, el color salta al color anterior cuando el usuario mueve el mouse antes de que se complete la animación.


Lo que quiero idealmente es poder hacer algo como esto:

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

Donde getClassContentsolo devolvería el contenido de la clase proporcionada. El punto clave es que de esta manera no tengo que mantener mis definiciones de estilo por todas partes, pero puedo mantenerlas en clases en mi hoja de estilo.

Johannes
fuente
1
¿Qué versiones de IE necesitas admitir? ¿Serías feliz con IE9? ¿O necesitas apoyar más abajo?
tw16
1
No me importa nada IE para ser honesto. Todo esto se ha probado solo con navegadores webkit (safari / chrome).
Johannes
como getClassContentes
sreginogemoh

Respuestas:

311

Dado que no está preocupado por IE, ¿por qué no usar transiciones CSS para proporcionar la animación y jQuery para cambiar las clases? Ejemplo en 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
fuente
14
A partir del 2015-06-12, esto es compatible con - IE 10+ - Chrome 26+ - FireFox 16+ - Safari 6.1+ - Opera 12.1+ -webkit, -moz, -o solo es necesario para navegadores incluso más antiguos. Probablemente pueda dejarlo afuera para ahorrar algo de espacio.
clst
3
@clst, preferiría la compatibilidad con los navegadores antiguos en lugar de ahorrar unos pocos bytes de espacio.
Arman H
96

Otra solución (pero requiere jQueryUI como lo señala Richard Neil Ilagan en los comentarios):

addClass, removeClass y toggleClass también acepta un segundo argumento; La duración del tiempo para ir de un estado a otro.

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

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

Omar Tariq
fuente
28
Tenga en cuenta que esto requiere jQuery UI. jQuery listo para usar no admite interpolación de animación para xxxClass()funciones.
Richard Neil Ilagan
@ Richard Neil Ilagan: Gracias por notificarme. Realmente extrañé ese punto.
Omar Tariq
44
¿Puede señalar qué archivo descargar e incluir en el archivo .html para que pueda usar jQueryUI solo para la interpolación de xxxClassanimación de esta manera?
nitrato de sodio
[jqueryui.com] (jqueryui.com) @sodiumnitrate
joe_young
1
Esta solución tampoco anima de la misma manera que slide () o animate (). El valor de milisegundos es un retraso, que no es una animación.
Solona Armstrong
38

Podrías usar jquery ui's switchClass, Heres un ejemplo:

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

O vea este jsfiddle .

por0
fuente
1
-1. No cumpliste con las restricciones 1, 2 y 3 que enumeré en la publicación original. Específicamente, switchClass maneja los requisitos 2 y 3 de manera deficiente.
Johannes
12

Solo necesita el jQuery UI effects-core (13KB), para permitir la duración de la adición (al igual que Omar Tariq señaló)

Patricio
fuente
5

Estaba investigando esto, pero quería tener una tasa de transición diferente para entrar y salir.

Esto es lo que terminé haciendo:

//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');
    });
});

Esto cambia instantáneamente el color de fondo a # 5eb4fc y luego vuelve lentamente a la normalidad durante 2 segundos.

Aquí hay un violín

Tj Gienger
fuente
2

Aunque la pregunta es bastante antigua, estoy agregando información que no está presente en otras respuestas.

El OP está utilizando stop () para detener la animación actual tan pronto como se complete el evento. Sin embargo, usar la combinación correcta de parámetros con la función debería ayudar. p.ej. stop (verdadero, verdadero) o stop (verdadero, falso) ya que esto afecta bien a las animaciones en cola.

El siguiente enlace ilustra una demostración que muestra los diferentes parámetros disponibles con stop () y cómo difieren de finish ().

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

Aunque el OP no tuvo problemas al usar JqueryUI, esto es para otros usuarios que pueden encontrarse con escenarios similares pero no pueden usar JqueryUI / también necesitan admitir IE7 y 8.

Anurag
fuente