Appearance
Les animations d'entrée et de sortie dans Angular
Note
Si vous ne connaissez pas les animations dans Angular, il est recommandé d'abord de lire la page La base des animations.
Les animations d'entrée et de sortie sont essentielles pour créer une expérience utilisateur fluide et professionnelle. Nous allons voir comment les mettre en place à travers un exemple concret : un système de notifications toast.
CONCEPT CLÉ
Les animations d'entrée (:enter) et de sortie (:leave) permettent de contrôler comment les éléments apparaissent et disparaissent de notre interface.
Avant tout: mise en place des animations
Si vous n'avez pas encore installé Angular Animations, vous pouvez le faire avec la commande suivante (vous pouvez le vérifier dans le fichier package.json
)
bash
ng add @angular/animations
Ensuite, allez dans le fichier app.config.ts
et ajoutez dans la liste des providers:
ts
import { AppComponent } from './app/app.component';
import { bootstrapApplication } from '@angular/platform-browser';
import { provideAnimationsAsync } from '@angular/platform-browser/animations';
bootstrapApplication(AppComponent, {
providers: [
provideAnimationsAsync()
]
});
Charger les animations dès le chargement de l'application
Si vous avez besoin d'animations dès le chargement de votre application, vous devrez utiliser le module d'animations chargé immédiatement plutôt que de manière asynchrone. Pour cela, importez provideAnimations
depuis @angular/platform-browser/animations
et utilisez-le à la place de provideAnimationsAsync
:
Implémentation du système de toast
Commençons par créer notre système de notifications toast :
ts
import { Component, input, inject } from '@angular/core';
import { animate, style, transition, trigger } from '@angular/animations';
import { ToastService } from './toast.service';
@Component({
selector: 'app-toast',
standalone: true,
template: `
@if (toastService.showToast()) {
<div class="toast" @toastAnimation>
{{ toastService.message() }}
</div>
}
`,
styles: `
.toast {
position: fixed;
right: 20px;
top: 20px;
padding: 1rem;
background: #333;
color: white;
border-radius: 4px;
}
`,
animations: [
trigger('toastAnimation', [
transition(':enter', [
style({ transform: 'translateX(100%)', opacity: 0 }),
animate('150ms ease-out', style({ transform: 'translateX(0)', opacity: 1 }))
]),
transition(':leave', [
animate('150ms ease-in', style({ transform: 'translateX(100%)', opacity: 0 }))
])
])
]
})
export class ToastComponent {
toastService = inject(ToastService)
}
ts
import { Injectable, signal } from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class ToastService {
showToast = signal(false);
message = signal('');
show(msg: string) {
this.message.set(msg);
this.showToast.set(true);
setTimeout(() => {
this.showToast.set(false);
}, 3000);
}
}
ts
import { Component, inject } from '@angular/core';
import { ToastComponent } from './toast.component';
import { ToastService } from './toast.service';
@Component({
selector: 'app-root',
standalone: true,
imports: [ToastComponent],
template: `
<app-toast />
<button (click)="toastService.show('Hello World!')">Afficher Toast</button>
`,
})
export class AppComponent {
toastService = inject(ToastService);
}
Notez que nous n'avons pas défini state
dans notre trigger. C'est parce que nous n'avons pas besoin de définir un état initial et final. Nous pouvons simplement utiliser les transitions :enter
et :leave
pour gérer l'animation. Donc, dans le template, nous ne mettons pas le binding dynamique [@toastAnimation]
sur le div mais juste @toastAnimation
.
L'animation d'entrée (:enter)
ts
transition(':enter', [
// Position initiale : décalé de 100% vers la droite et invisible
style({ transform: 'translateX(100%)', opacity: 0 }),
// Animation vers la position finale : centré et visible
animate('150ms ease-out', style({ transform: 'translateX(0)', opacity: 1 }))
])
Ici, la particularité est que l'animation d'entrée est déclenchée par le changement d'état :enter
. C'est un alias pour la transition void => *
.
L'animation de sortie (:leave)
ts
transition(':leave', [
// Animation vers la position finale : sort vers la droite en devenant invisible
animate('150ms ease-in', style({ transform: 'translateX(100%)', opacity: 0 }))
])
Ici, l'animation de sortie est déclenchée par le changement d'état :leave
. C'est un alias pour la transition * => void
.
Note
Les animations :enter
et :leave
sont des alias pour les transitions void => *
et * => void
donc elles ne fonctionnent que lorsque les éléments sont ajoutés ou supprimés du DOM par Angular (par exemple avec @if
ou @for
).
IMPORTANT
Les comportements d'entrée/sortie peuvent parfois être déroutants. En règle générale, considérez que tout élément ajouté au DOM par Angular passe par la transition :enter
. Seuls les éléments directement supprimés du DOM par Angular passent par la transition :leave
. Par exemple, la vue d'un élément est supprimée du DOM parce que son parent est en train d'être supprimé du DOM.