AngularJS es un jugador importante en el mundo del marco JavaScript MVW. ‘Pensar en Angular’ es algo que puede eludir a los desarrolladores que provienen de jQuery u otras bibliotecas pesadas de manipulación DOM. Existe una ‘manera angular’ de hacer las cosas que se basa en datos en lugar de usar DOM transversal para impulsar los cambios de vista, y eso puede ser difícil de visualizar cuando se trata de algo como animaciones. Juntos, veremos exactamente cómo animar con las herramientas proporcionadas por el equipo de Angular.
ngAnimate
y el $animate
Servicio
El equipo central de Angular nos dio la ngAnimate
módulo para que podamos dar a nuestras aplicaciones una forma de animar a partir de una ‘forma Angular’ basada en datos, y para que podamos conectarnos a los eventos que Angular emite a través de algunas de sus directivas integradas.
Angular, a diferencia de jQuery, se enfoca en vincular nuestra vista a un objeto JavaScript mediante el uso de controladores. Este enfoque nos permite vincular valores de vista como campos de entrada directamente a un valor correspondiente en un objeto de JavaScript y desencadenar cambios de vista a través de cambios de datos, o viceversa.
Entonces, ¿cómo conectamos las animaciones con estos eventos si pudieran ocurrir desde la vista o desde el objeto correspondiente que se está cambiando?
Primero, debemos agregar ngAnimate
a nuestro proyecto.
Incluyendo Animación Angular en nuestro Proyecto
A partir de 1.2.0, las animaciones ya no forman parte del núcleo de Angular, sino que se encuentran en su propio módulo separado: ngAnimate
. Para usar el $animate
servicio, necesitamos incluir la biblioteca de animación después de Angular en nuestro archivo HTML, así: js/lib/angular-animate.js
Como alternativa, también puede utilizar el CDN o bower
instalar angular-animate
:
$ bower install --save angular-animate
Independientemente de cómo elija instalarlo, asegúrese de incluirlo en su archivo fuente, así:
<script src="https://css-tricks.com/animations-the-angular-way/js/lib/angular.js"></script>
<script src="js/lib/angular-animate.js"></script>
A continuación, tendremos que incluir el ngAnimate
módulo como una dependencia a nuestra aplicación. Esto se puede hacer cuando creamos una instancia de nuestra aplicación Angular, así:
angular.module('myApp', ['ngAnimate']);
Ahora eso ngAnimate
está incluido en nuestro proyecto (y siempre que no tengamos un error de inyector o algo así en nuestra consola) ¡podemos comenzar a crear animaciones con Angular!
Transiciones CSS3
La forma más fácil de incluir animaciones en cualquier aplicación es mediante transiciones CSS3. Esto se debe a que están completamente basados en clases, lo que significa que la animación se define en una clase y, siempre que usemos esa clase en nuestro HTML, la animación funcionará en el navegador.
Las transiciones CSS son animaciones que permiten que un elemento HTML cambie constantemente de un estilo a otro. Para definir una transición, debemos especificar el elemento al que queremos agregar un efecto y la duración de dicho efecto.
Primero, echemos un vistazo a un ejemplo simple de una transición CSS3, y luego podemos ver cómo hacer uso de este conocimiento desde una aplicación Angular basada en datos.
Vamos a crear un sencillo div
dentro de un contenedor div
y aplicarle dos clases: una para el estilo básico y otra para nuestra transición.
<div class="container">
<div class="box rotate"></div>
</div>
Ahora podemos agregar transiciones para el estado de desplazamiento o el estado estático del elemento:
.box {
margin: 50px auto;
background: #5FCF80;
width: 150px;
height: 150px;
}
.box:hover {
transform: rotate(360deg);
background: #9351A6;
border-radius: 50%;
}
.rotate {
transition: all 0.5s ease-in-out;
}
.rotate:hover {
transition: all 1s ease-in-out;
}
Esto aplica dos estados a nuestro div
: un estado normal y otro para cuando pasemos el cursor sobre el div
. Las transiciones definidas en el .rotate
y .rotate:hover
Las clases le dicen al navegador cómo hacer la transición entre estos dos estados cuando activamos el hover
y mouseleave
eventos.
Terminamos con un efecto como este:
Transición básica de CSS3
Animación CSS3 basada en datos angulares
Ahora veamos cómo podríamos hacer algo así en una aplicación Angular y vincular esta misma funcionalidad a algunos datos dentro de nuestra aplicación.
En lugar de hacer esta transición en :hover
, podemos crear una animación simple vinculando transiciones a una clase, .rotate
y cree una clase para los estados de “caja” y “círculo” del div
. Esto nos permite cambiar entre clases usando el ng-class
Directiva integrada en Angular.
.box {
margin: 20px auto;
background: #5FCF80;
width: 150px;
height: 150px;
}
.circle {
transform: rotate(360deg);
background: #9351A6;
border-radius: 50%;
margin: 20px auto;
width: 150px;
height: 150px;
}
.rotate {
transition: all 1s ease-in-out;
}
Para hacer esto, necesitaremos configurar nuestra aplicación Angular y crear una declaración condicional en el ng-class
directiva para cambiar la clase en función del valor de un booleano en el $scope
.
<div ng-app="myApp" ng-controller="MainCtrl">
<div class="container">
<input type="checkbox" ng-model="boxClass" />
<div class="box rotate" ng-class="{'box': boxClass, 'circle': !boxClass} "></div>
</div>
</div>
Ahora configuremos nuestro JavaScript:
angular.module('myApp', [])
.controller('MainCtrl', function($scope) {
$scope.boxClass = true;
});
Aquí, vinculamos el valor booleano que se adjunta a $scope.boxClass
a si el elemento debe o no tener la .box
o .circle
clase. Si el valor booleano es verdadero, entonces el elemento tendrá el .box
clase. Si es falsa, tendrá la .circle
clase. Esto nos permite activar una transición CSS3 cambiando el valor de nuestros datos, sin manipulación alguna del DOM.
Esto no utiliza el $animate
servicio, pero quería proporcionar un ejemplo de una instancia en la que podría usar CSS3 solo y no tener que depender de $animate
y ngAnimate
.
El resultado de esto es una animación que se desencadena estrictamente por un cambio de datos cuando cambiamos el booleano subyacente al hacer clic en la casilla de verificación.
Transición de CSS3 basada en datos angulares
Transiciones con $animate
Si queremos aprovechar las transiciones de CSS3 y el $animate
servicio, entonces necesitamos saber un par de cosas sobre cómo $animate
trabaja detrás de escena.
El $animate
El servicio admite varias directivas integradas en Angular. Esto está disponible sin ninguna otra configuración y nos permite crear animaciones para nuestras directivas en CSS simple. Para usar animaciones de esta manera, ni siquiera necesita incluir $animate
en su controlador; solo incluye ngAnimate
como una dependencia de su módulo Angular.
Una vez que incluya ngAnimate
en su módulo, hay un cambio en la forma en que Angular maneja ciertas directivas integradas. Angular comenzará a conectarse y monitorear estas directivas, y agregará clases especiales al elemento en la activación de ciertos eventos. Por ejemplo, cuando agrega, mueve o elimina un elemento de una matriz que está siendo utilizada por el ngRepeat
directiva, Angular ahora detectará ese evento y agregará una serie de clases a ese elemento en el ngRepeat
.
Aquí puedes ver las clases que ngAnimate
agrega en el evento enter de un ngRepeat
:
ngRepeat
Clases de eventos
Las clases CSS adjuntas toman la forma de ng-{EVENT}
y ng-{EVENT}-active
para eventos estructurales como entrar, moverse o salir. Pero, para animaciones basadas en clases, toma la forma de {CLASS}-add
, {CLASS}-add-active
, {CLASS}-remove
, y {CLASS}-remove-active
. Las excepciones a estas reglas son ng-hide
y ng-show
. Ambas directivas tienen eventos de agregar y quitar que se activan, al igual que ng-class
, pero ambos comparten la .ng-hide
class, que se agrega o elimina cuando corresponde. también verás ngAnimate
Agrega un .ng-animate
clase a algunas de estas directivas sobre animación.
A continuación se muestra una tabla que ilustra algunas de las directivas integradas, los eventos que se activan y las clases que se agregan temporalmente cuando agrega ngAnimate
a su proyecto:
Directivas incorporadas $animate
Eventos
Directiva | Eventos) | Clases |
---|---|---|
ngRepetir | ingresar | ng-enter, ng-enter-activo |
salir | ng-permiso, ng-permiso-activo | |
Muevete | ng-movimiento, ng-movimiento-activo | |
ngView, ngInclude, ngSwitch, ngIf | ingresar | ng-enter, ng-enter-activo |
salir | ng-permiso, ng-permiso-activo | |
Clase ng | agregar | ng-añadir, ng-añadir-activo |
retirar | ng-eliminar, ng-eliminar-activo | |
ngMostrar, ngOcultar | agregar eliminar | ng-ocultar |
Angular detectará automáticamente que CSS está adjunto a una animación cuando se activa la animación y agregará el .ng-{EVENT}-active
clase hasta que la animación haya seguido su curso. Luego eliminará esa clase y cualquier otra clase agregada del DOM.
A continuación se muestra un ejemplo del uso de transiciones CSS3 para animar un ngRepeat
directiva. En él, adjuntamos una transición a la clase base:.fade
en este caso, y luego aprovechar las clases que ngAnimate
agregará a la li
elementos cuando se agregan y eliminan de la matriz. Una vez más, esto nos permite tener animaciones basadas en datos, al estilo Angular.
ngRepeat
$animate
Transiciones CSS3 impulsadas
Como podemos ver, Angular ngAnimate
nos brinda la capacidad de aprovechar fácilmente los eventos y aprovechar el poder de las transiciones CSS3 para hacer algunas animaciones naturales realmente geniales en nuestras directivas. Esta es, con mucho, la forma más fácil en que podemos hacer animaciones para nuestras aplicaciones Angular, pero ahora veremos algunas opciones más complejas.
Animaciones CSS3
Las animaciones CSS3 son más complicadas que las transiciones, pero tienen mucho de la misma implementación en el ngAnimate
lado. Sin embargo, en el CSS usaremos un @keyframes
regla para definir nuestra animación. Esto se hace de la misma manera que hicimos nuestra transición básica anteriormente, excepto que usamos el animation
palabra clave en nuestro CSS y dar a la animación un nombre como este:
@keyframes appear {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes disappear {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
Aquí hemos creado un appear
y disappear
animación que se puede activar a través de CSS en el lugar donde estaba nuestra transición antes.
.fade.ng-enter {
animation: 2s appear;
}
.fade.ng-leave {
animation: 1s disappear;
}
La diferencia esta vez, como puedes ver arriba, es que ya no tenemos que usar .ng-enter-active
o .ng-leave-active
, sino que podemos adjuntar la animación a .ng-leave
y .ng-active
y la animación se disparará en los momentos apropiados debido a ngAnimate
. Esta no es una forma particularmente mejor de hacerlo que nuestro método de transición anterior, pero ilustra cómo usar animaciones CSS3, que pueden ser MUCHO más poderosas que este simple efecto.
El resultado final de esta animación cuando se aplica a nuestra lista de compras anterior ngRepeat
ejemplo se verá algo como esto:
ngRepeat $animate
Animaciones CSS3 potenciadas
Animaciones JavaScript
Ahora para el elefante en la habitación: Animaciones JavaScript con AngularJS.
Angular está completamente basado en datos con su elegante enlace de datos bidireccional, es decir, hasta que no lo es. Esta es una de las cosas más confusas de pasar de jQuery a Angular. Se nos dice que volvamos a aprender cómo pensamos y que descartemos la manipulación del DOM en favor de los enlaces, pero luego, en algún momento, nos lo devuelven más tarde. Bueno, bienvenido a ese punto de círculo completo.
La animación de JavaScript tiene una gran ventaja: JavaScript está en todas partes y tiene una aceptación más amplia que algunas animaciones CSS3 avanzadas. Ahora, si solo está apuntando a navegadores modernos, entonces esto probablemente no será un problema para usted, pero si necesita admitir navegadores que no admiten transiciones CSS, entonces puede registrar fácilmente una animación JavaScript con Angular y usarla otra vez. y más en sus directivas. Básicamente, JavaScript es más compatible con los navegadores más antiguos y, por lo tanto, también lo son las animaciones de JavaScript.
cuando incluyes ngAnimate
como una dependencia de su módulo Angular, agrega el animation
método a la API del módulo. Lo que esto significa es que ahora puede usarlo para registrar sus animaciones de JavaScript y aprovechar los ganchos angulares en directivas integradas como ngRepeat
. Este método toma dos argumentos: className(string)
y animationFunction(function)
.
El className
el parámetro es simplemente la clase a la que se dirige, y la función de animación puede ser una función anónima que recibirá tanto el element
y done
parámetros cuando se llama. El element
el parámetro es solo eso, el elemento como un objeto jqLite, y el done
El parámetro es una función a la que debe llamar cuando su animación termine de ejecutarse para que angular pueda continuar en su camino y sepa que desencadenar que el evento se ha completado.
Sin embargo, lo principal a comprender aquí es lo que debe devolverse de la función de animación. Angular buscará que se devuelva un objeto con claves que coincidan con los nombres de los eventos en los que desea activar animaciones para esa directiva en particular. Si no está seguro de lo que admite la directiva, simplemente consulte mi tabla anterior.
Así que para nuestro ngRepeat
ejemplo, se vería algo como esto:
return {
enter: function(element, done) {
// Animation code goes here
// Use done() in your animation callback
},
move: function(element, done) {
// Animation code goes here
// Use done() in your animation callback
},
leave: function(element, done) {
// Animation code goes here
// Use done() in your animation callback
}
}
Y si unimos todo esto con el mismo viejo aburrido (lo siento) ngRepeat
ejemplo de lista de compras y use jQuery para las animaciones reales:
var app = angular.module('myApp', ['ngAnimate'])
.animation('.fade', function() {
return {
enter: function(element, done) {
element.css('display', 'none');
$(element).fadeIn(1000, function() {
done();
});
},
leave: function(element, done) {
$(element).fadeOut(1000, function() {
done();
});
},
move: function(element, done) {
element.css('display', 'none');
$(element).slideDown(500, function() {
done();
});
}
}
})
Ahora, permítanme desglosar lo que está pasando.
Podemos deshacernos de cualquier CSS que teníamos previamente en el .fade
clase, pero aún necesitamos algún tipo de clase para registrar la animación. Entonces, por el bien de la continuidad, solo usé el viejo y bueno .fade
clase.
Básicamente, lo que sucede aquí es que Angular registrará sus funciones de animación y las llamará en ese elemento específico cuando ese evento tenga lugar en esa directiva. Por ejemplo, llamará a su enter
función de animación cuando un nuevo artículo entra en un ngRepeat
.
Todas estas son animaciones jQuery muy básicas y no entraré en ellas aquí, pero vale la pena señalar que ngRepeat
agregará automáticamente el nuevo elemento al DOM cuando se agregue a la matriz, y dicho elemento será inmediatamente visible. Por lo tanto, si está tratando de lograr un efecto de atenuación con JavaScript, debe configurar la visualización en ninguno inmediatamente antes de atenuarla. Esto es algo que podría evitar con las animaciones y transiciones CSS.
Unámoslo todo y veamos qué obtenemos:
ngRepeat $animate
Animaciones de JavaScript con tecnología
Conclusión
El ngAnimate
módulo es un poco de un nombre engañoso.
Por supuesto, no podría encontrar un nombre mejor si lo intentara, pero en realidad no HACE ninguna animación. Más bien, le brinda acceso al ciclo de eventos de Angular para que pueda realizar su propia manipulación DOM o animaciones CSS3 en el punto adecuado basado en datos. Esto es poderoso por derecho propio porque lo estamos haciendo ‘a la manera angular’ en lugar de tratar de forzar nuestra propia lógica y tiempo en un marco muy particular.
Otro beneficio de hacer tus animaciones con ngAnimate
es que una vez que escribe sus animaciones para esa directiva, se pueden empaquetar muy bien y pasar a otros proyectos con relativa facilidad. Esto, en mi libro, siempre es algo bueno.