Guías Detalladas
Animations

Animando tus aplicaciones con animate.enter y animate.leave

Las animaciones bien diseñadas pueden hacer que tu aplicación sea más divertida y fácil de usar, pero no son solo cosméticas. Las animaciones pueden mejorar tu aplicación y la experiencia del usuario de varias maneras:

  • Sin animaciones, las transiciones de páginas web pueden parecer abruptas y bruscas
  • El movimiento mejora enormemente la experiencia del usuario, así que las animaciones dan a los usuarios la oportunidad de detectar la respuesta de la aplicación a sus acciones
  • Las buenas animaciones pueden dirigir suavemente la atención del usuario a lo largo de un flujo de trabajo

Angular proporciona animate.enter y animate.leave para animar los elementos de tu aplicación. Estas dos características aplican clases CSS de entrada y salida en los momentos apropiados o llaman funciones para aplicar animaciones de bibliotecas de terceros. animate.enter y animate.leave no son directivas. Son APIs especiales soportadas directamente por el compilador de Angular. Pueden ser usadas en elementos directamente y también pueden ser usadas como un enlace host.

animate.enter

Puedes usar animate.enter para animar elementos a medida que entran al DOM. Puedes definir animaciones de entrada usando clases CSS con transiciones o animaciones de keyframes.

src/app/enter.ts

import {Component, signal} from '@angular/core';@Component({  selector: 'app-enter',  templateUrl: 'enter.html',  styleUrls: ['enter.css'],})export class Enter {  isShown = signal(false);  toggle() {    this.isShown.update((isShown) => !isShown);  }}

src/app/enter.html

<h2><code>animate.enter</code> Example</h2><button type="button" (click)="toggle()">Toggle Element</button>@if (isShown()) {  <div class="enter-container" animate.enter="enter-animation">    <p>The box is entering.</p>  </div>}

src/app/enter.css

:host {  display: block;  height: 200px;}.enter-container {  border: 1px solid #dddddd;  margin-top: 1em;  padding: 20px 20px 0px 20px;  font-weight: bold;  font-size: 20px;}.enter-animation {  animation: slide-fade 1s;}@keyframes slide-fade {  from {    opacity: 0;    transform: translateY(20px);  }  to {    opacity: 1;    transform: translateY(0);  }}

Cuando la animación se completa, Angular elimina la clase o clases que especificaste en animate.enter del DOM. Las clases de animación solo están presentes mientras la animación está activa.

NOTA: Cuando se usan múltiples animaciones de keyframes o propiedades de transición en un elemento, Angular elimina todas las clases solo después de que la animación más larga se haya completado.

Puedes usar animate.enter con cualquier otra característica de Angular, como control de flujo o expresiones dinámicas. animate.enter acepta tanto una cadena de clase única (con múltiples clases separadas por espacios), o un array de cadenas de clases.

Una nota rápida sobre el uso de transiciones CSS: Si eliges usar transiciones en lugar de animaciones de keyframes, las clases agregadas al elemento con animate.enter representan el estado al que la transición animará. Tu CSS de elemento base es cómo se verá el elemento cuando no se ejecuten animaciones, lo cual es probablemente similar al estado final de la transición CSS. Así que todavía necesitarías emparejarlo con @starting-style para tener un estado desde apropiado para que tu transición funcione.

src/app/enter-binding.ts

import {Component, signal} from '@angular/core';@Component({  selector: 'app-enter-binding',  templateUrl: 'enter-binding.html',  styleUrls: ['enter-binding.css'],})export class EnterBinding {  isShown = signal(false);  toggle() {    this.isShown.update((isShown) => !isShown);  }  enterClass = signal('enter-animation');}

src/app/enter-binding.html

<h2><code>animate.enter</code> Binding Example</h2><button type="button" (click)="toggle()">Toggle Element</button>@if (isShown()) {  <div class="enter-container" [animate.enter]="enterClass()">    <p>The box is entering.</p>  </div>}

src/app/enter-binding.css

:host {  display: block;  height: 200px;}.enter-container {  border: 1px solid #dddddd;  margin-top: 1em;  padding: 20px 20px 0px 20px;  font-weight: bold;  font-size: 20px;}.enter-animation {  animation: slide-fade 1s;}@keyframes slide-fade {  from {    opacity: 0;    transform: translateY(20px);  }  to {    opacity: 1;    transform: translateY(0);  }}

animate.leave

Puedes usar animate.leave para animar elementos a medida que salen del DOM. Puedes definir animaciones de salida usando clases CSS con transformaciones o animaciones de keyframes.

src/app/leave.ts

import {Component, signal} from '@angular/core';@Component({  selector: 'app-leave',  templateUrl: 'leave.html',  styleUrls: ['leave.css'],})export class Leave {  isShown = signal(false);  toggle() {    this.isShown.update((isShown) => !isShown);  }}

src/app/leave.html

<h2><code>animate.leave</code> Example</h2><button type="button" (click)="toggle()">Toggle Element</button>@if (isShown()) {  <div class="leave-container" animate.leave="leaving">    <p>Goodbye</p>  </div>}

src/app/leave.css

:host {  display: block;  height: 200px;}.leave-container {  border: 1px solid #dddddd;  margin-top: 1em;  padding: 20px 20px 0px 20px;  font-weight: bold;  font-size: 20px;  opacity: 1;  transition: opacity 200ms ease-in;  @starting-style {    opacity: 0;  }}.leaving {  opacity: 0;  transform: translateY(20px);  transition: opacity 500ms ease-out, transform 500ms ease-out;}

Cuando la animación se completa, Angular elimina automáticamente el elemento animado del DOM.

NOTA: Cuando se usan múltiples animaciones de keyframes o propiedades de transición en un elemento, Angular espera para eliminar el elemento solo después de que la más larga de esas animaciones se haya completado.

animate.leave también puede ser usado con signals y otros enlaces. Puedes usar animate.leave con una clase única o múltiples clases. Ya sea especificándolo como una cadena simple con espacios o un array de cadenas.

src/app/leave-binding.ts

import {Component, signal} from '@angular/core';@Component({  selector: 'app-leave-binding',  templateUrl: 'leave-binding.html',  styleUrls: ['leave-binding.css'],})export class LeaveBinding {  isShown = signal(false);  toggle() {    this.isShown.update((isShown) => !isShown);  }  farewell = signal('leaving');}

src/app/leave-binding.html

<h2><code>animate.leave</code> Binding Example</h2><button type="button" (click)="toggle()">Toggle Element</button>@if (isShown()) {  <div class="leave-container" [animate.leave]="farewell()">    <p>Goodbye</p>  </div>}

src/app/leave-binding.css

:host {  display: block;  height: 200px;}.leave-container {  border: 1px solid #dddddd;  margin-top: 1em;  padding: 20px 20px 0px 20px;  font-weight: bold;  font-size: 20px;  opacity: 1;  transition: opacity 200ms ease-in;  @starting-style {    opacity: 0;  }}.leaving {  opacity: 0;  transform: translateY(20px);  transition: opacity 500ms ease-out, transform 500ms ease-out;}

Enlaces de eventos, funciones y bibliotecas de terceros

Tanto animate.enter como animate.leave soportan sintaxis de enlace de eventos que permite llamadas a funciones. Puedes usar esta sintaxis para llamar a una función en el código de tu componente o utilizar bibliotecas de animación de terceros, como GSAP, anime.js, o cualquier otra biblioteca de animación JavaScript.

src/app/leave-event.ts

import {AnimationCallbackEvent, Component, signal} from '@angular/core';@Component({  selector: 'app-leave-binding',  templateUrl: 'leave-event.html',  styleUrls: ['leave-event.css'],})export class LeaveEvent {  isShown = signal(false);  toggle() {    this.isShown.update((isShown) => !isShown);  }  leavingFn(event: AnimationCallbackEvent) {    // Example of calling GSAP    // gsap.to(event.target, {    //   duration: 1,    //   x: 100,    //   // arrow functions are handy for concise callbacks    //   onComplete: () => event.animationComplete()    // });    event.animationComplete();  }}

src/app/leave-event.html

<h2><code>animate.leave</code> Function Example</h2><button type="button" (click)="toggle()">Toggle Element</button>@if (isShown()) {  <div class="leave-container" (animate.leave)="leavingFn($event)">    <p>Goodbye</p>  </div>}

src/app/leave-event.css

:host {  display: block;  height: 200px;}.leave-container {  border: 1px solid #dddddd;  margin-top: 1em;  padding: 20px 20px 0px 20px;  font-weight: bold;  font-size: 20px;  opacity: 1;  transition: opacity 200ms ease-in;  @starting-style {    opacity: 0;  }}.leaving {  opacity: 0;  transform: translateY(20px);  transition: opacity 500ms ease-out, transform 500ms ease-out;}

El objeto $event tiene el tipo AnimationCallbackEvent. Incluye el elemento como el target y proporciona una función animationComplete() para notificar al framework cuando la animación termina.

IMPORTANTE: Debes llamar a la función animationComplete() cuando uses animate.leave para que Angular elimine el elemento.

Si no llamas a animationComplete() cuando usas animate.leave, Angular llama a la función automáticamente después de un retraso de cuatro segundos. Puedes configurar la duración del retraso proporcionando el token MAX_ANIMATION_TIMEOUT en milisegundos.

  { provide: MAX_ANIMATION_TIMEOUT, useValue: 6000 }

Pruebas

TestBed proporciona soporte integrado para habilitar o deshabilitar animaciones en tu entorno de prueba. Las animaciones CSS requieren un navegador para ejecutarse, y muchas de las APIs no están disponibles en un entorno de prueba. Por defecto, TestBed deshabilita las animaciones para ti en tus entornos de prueba.

Si quieres probar que las animaciones están animando en una prueba de navegador, por ejemplo una prueba end-to-end, puedes configurar TestBed para habilitar animaciones especificando animationsEnabled: true en tu configuración de prueba.

  TestBed.configureTestingModule({animationsEnabled: true});

Esto configurará las animaciones en tu entorno de prueba para que se comporten normalmente.

NOTA: Algunos entornos de prueba no emiten eventos de animación como animationstart, animationend y sus equivalentes de eventos de transición.

Más sobre animaciones de Angular

También puede que te interese lo siguiente: